HDU5274 Dylans loves tree(树链剖分)很巧的点权更新

Dylans loves tree

Accepts: 49

Submissions: 262

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 131072/131072 K (Java/Others)

问题描述

Dylans有一棵N个点的树。每个点有点权。树上节点标号为1∼N。
他得到了Q个询问,形式如下:
①0 x y:把第x个点的点权修改为y。
②1 x y:对于x∼y路径上的每一种点权,是否都出现偶数次?
保证每次询问的路径上最多只有一种点权的出现次数是奇数次。

1≤N,Q≤100000, 点权A[i]∈N,且都 ≤100000

输入描述

第一行一个正整数T表示数据组数(T≤3且最多只有一组数据N>1000)
第一行两个数N、Q表示树的点数和询问个数。
接下来N?1行每行一对数(x,y)表示树上的一条边。
接下来一行N个数表示每个点的点权。
接下来Q行每行三个数(opt,x,y)表示询问。

输出描述

对于每个②询问,如果全是偶数输出“-1",否则输出出现奇数次的权值。

输入样例

1
3 2
1 2
2 3
1 1 1
1 1 2
1 1 3

输出样例

-1
1

Hint

hack数据里N和Q必须小于等于10000,且对于读入的每一行末尾不应该有多余的空格。
解题:

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<map>
using namespace std;
const int N = 100005;
#define LL __int64
struct EDG{
    int to,next;
}edg[N*2];
int eid,head[N];
int fath[N],deep[N],top[N],num[N],son[N],p[N],pos;
void init(){
    pos=0; eid=0;
    memset(head,-1,sizeof(head));
}
void addEdg(int u,int v){
    edg[eid].to=v; edg[eid].next=head[u]; head[u]=eid++;
    edg[eid].to=u; edg[eid].next=head[v]; head[v]=eid++;
}
void dfs(int u,int pre,int d){
    fath[u]=pre; num[u]=1; deep[u]=d; son[u]=-1;
    for(int i=head[u]; i!=-1; i=edg[i].next){
        int v=edg[i].to;
        if(v==pre)continue;
        dfs(v,u,d+1);
        num[u]+=num[v];
        if(son[u]==-1||num[son[u]]<num[v])
            son[u]=v;
    }
}
void getpos(int u,int root){
    top[u]=root;
    p[u]=++pos;
    if(son[u]==-1)
        return ;
    getpos(son[u],root);
    for(int i=head[u]; i!=-1; i=edg[i].next){
        int v=edg[i].to;
        if(son[u]==v||v==fath[u])
            continue;
        getpos(v,v);
    }
}
int root[N*3];  //记录当前区间内所有值的xor
int a[N];
void build(int l,int r,int k){

    if(l==r){
       root[k]=a[l];
       return ;
    }
    int m=(l+r)>>1;
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    root[k]=root[k<<1]^root[k<<1|1];
}
void updata(int l,int r,int k,int id,int vule){
    if(l==r){
        root[k]=vule;
        return ;
    }
    int m=(l+r)>>1;
    if(id<=m)
        updata(l,m,k<<1,id,vule);
    else
        updata(m+1,r,k<<1|1,id,vule);
    root[k]=root[k<<1]^root[k<<1|1];
}
int query(int l,int r,int k,int L,int R){
    if(L<=l&&r<=R){
        return root[k];
    }
    int m=(l+r)>>1 , ans=0;
    if(L<=m)
       ans^= query(l,m,k<<1,L,R);
    if(m<R)
        ans^=query(m+1,r,k<<1|1,L,R);
    return ans;
}
void swp(int &aa,int &bb){
    int tt=aa; aa=bb; bb=tt;
}
int Operat(int u,int v){
    int fu=top[u] , fv=top[v],ans=0;
    while(fu!=fv){
        if(deep[fu]<deep[fv]){
            swp(fu,fv); swp(u,v);
        }
       ans^= query(1,pos,1,p[fu],p[u]);

       u=fath[fu]; fu=top[u];
    }
    if(deep[u]>deep[v])
        swp(u,v);
    ans^=query(1,pos,1,p[u],p[v]);

    return ans;
}

int main()
{
   int T,n,q,val[N],u,v;
   scanf("%d",&T);
   while(T--){
    scanf("%d%d",&n,&q);
    init();
    for(int i=1; i<n; i++)
    {
        scanf("%d%d",&u,&v);
        addEdg(u,v);
    }
    for(int i=1; i<=n; i++){
        scanf("%d",&val[i]);
        val[i]++;
    }

    dfs(1,1,1);
    getpos(1,1);
    for(int i=1; i<=n; i++)
        a[p[i]]=val[i];

    build(1,pos,1);
    while(q--){
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==0)
            updata(1,pos,1,p[x],y+1);//加1
        else{
            printf("%d\n",Operat(x,y)-1);//减1
        }
    }
   }
    return 0;
}

时间: 2024-10-14 20:14:34

HDU5274 Dylans loves tree(树链剖分)很巧的点权更新的相关文章

HDU5274 Dylans loves tree(树链剖分+异或)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5274 题意很简单,输入以后,查询的时候 0 x y,是把x点改成y. 1 x y,是查询[x,y]中,数字出现的次数是否都是偶数,出现奇数的数字<=1. 都是偶数的话,输出-1,有奇数的话,输出奇数的权值. 思路:这题也是一个裸题,但是这题的线段树维护的比较巧妙,因为一个数异或自己偶数次就是0,所以求一个区间异或和就行了.但是有个地方要注意,就是权值为0的话,异或自己,奇数次也是0.所以可以把所有的权

SPOJ375 Query on a tree 树链剖分

SPOJ375  Query on a tree   树链剖分 no tags You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

【BZOJ-4353】Play with tree 树链剖分

4353: Play with tree Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 31  Solved: 19[Submit][Status][Discuss] Description 给你一棵包含N个节点的树,设每条边一开始的边权为0,现在有两种操作: 1)给出参数U,V,C,表示把U与V之间的路径上的边权变成C(保证C≥0) 2)给出参数U,V,C,表示把U与V之间的路径上的边权加上C.但是如果U至V之间路径某条边的边权加上C小于0,那

poj 3237 Tree 树链剖分+线段树

Description You are given a tree with N nodes. The tree's nodes are numbered 1 through N and its edges are numbered 1 through N ? 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions

[Codechef - ADITREE] Adi and the Tree - 树链剖分,线段树

[Codechef - ADITREE] Adi and the Tree Description 树上每个节点有一个灯泡,开始所有灯泡都是熄灭的.每次操作给定两个数 \(a,b\) ,将 \(a,b\) 这两个节点的灯的状态改变.定义某个状态的权值为,将树上所有亮点两两配对,每个对的权值的总和最小值.其中一个配对的权值定义为这两个点之间的距离.求出每次操作后的权值. Solution 很容易发现如果我们将每个亮点到树根的路径染色,那么染色次数为奇数的路径就会被统计入答案. 所以只需要维护布尔值

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每次更新异或1就可以. 熟悉线段树成段更新就很简单了,最初姿势不对一直wa,还是没有彻底理解lazy标记啊. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace st