P2420 让我们异或吧

https://www.luogu.com.cn/problem/P2420

对于异或,就是将之前的求和的+号改为^ 即可 其他完全一样

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long LL;
  4 const int maxn=200000+10;
  5 int n,m,r;
  6 //见题意
  7 int w[maxn],wt[maxn];
  8 //链式前向星数组,w[]、wt[]初始点权数组
  9 int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
 10 //son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点
 11 //查询答案
 12 struct node
 13 {
 14     int v,w,nxt;
 15 }G[maxn<<2]; int head[maxn]; int num;
 16 struct tre
 17 {
 18     int l,r,lazy,sum;
 19     int mx,mn;
 20 }tree[maxn<<2];
 21 void add(int u,int v,int w)
 22 {
 23     G[++num].v=v;G[num].w=w;G[num].nxt=head[u];head[u]=num;
 24     G[++num].v=u;G[num].w=w;G[num].nxt=head[v];head[v]=num;
 25 }
 26 void build(int l,int r,int root){
 27     tree[root].l=l;tree[root].r=r;
 28     tree[root].sum=tree[root].lazy=0;
 29     tree[root].mx=-1001;
 30     tree[root].mn=1001;
 31     if(l==r){
 32         tree[root].sum=wt[l];
 33         tree[root].mn=wt[l];
 34         tree[root].mx=wt[l];
 35         return;
 36     }
 37     int mid=l+r>>1;
 38     build(l,mid,root<<1);
 39     build(mid+1,r,root<<1|1);
 40     tree[root].sum=tree[root<<1].sum^tree[root<<1|1].sum;
 41 }
 42 
 43 int query(int l,int r,int root){
 44     int L=tree[root].l;int R=tree[root].r;
 45     if(l<=L&&R<=r){
 46         return tree[root].sum;
 47     }
 48     int mid=L+R>>1;
 49     int ans=0;
 50     if(l<=mid) ans^=query(l,r,root<<1);
 51     if(r>mid)  ans^=query(l,r,root<<1|1);
 52     return ans;
 53 }
 54 
 55 void dfs1(int u,int f,int deep){//x当前节点,f父亲,deep深度
 56     dep[u]=deep;//标记每个点的深度
 57     fa[u]=f;//标记每个点的父亲
 58     siz[u]=1;//标记每个非叶子节点的子树大小
 59     int maxson=-1;//记录重儿子的儿子数
 60     for(int i=head[u];i!=-1;i=G[i].nxt){
 61         int v=G[i].v;
 62         if(v==f)continue;//若为父亲则continue
 63         w[v]=G[i].w;
 64         dfs1(v,u,deep+1);//dfs其儿子
 65         siz[u]+=siz[v];//把它的儿子数加到它身上
 66         if(siz[v]>maxson)son[u]=v,maxson=siz[v];//标记每个非叶子节点的重儿子编号
 67     }
 68 }
 69 
 70 void dfs2(int u,int topf){//x当前节点,topf当前链的最顶端的节点
 71     id[u]=++cnt;//标记每个点的新编号
 72     wt[cnt]=w[u];//把每个点的初始值赋到新编号上来
 73     top[u]=topf;//这个点所在链的顶端
 74     if(!son[u])return;//如果没有儿子则返回
 75     dfs2(son[u],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理
 76     for(int i=head[u];i!=-1;i=G[i].nxt){
 77         int v=G[i].v;
 78         if(v==fa[u]||v==son[u])continue;
 79         dfs2(v,v);//对于每一个轻儿子都有一条从它自己开始的链
 80     }
 81 }
 82 int qRange(int x,int y){
 83     int ans=0;
 84     while(top[x]!=top[y]){//当两个点不在同一条链上
 85         if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
 86         ans^=query(id[top[x]],id[x],1);//ans加上x点到x所在链顶端 这一段区间的点权和
 87         x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
 88     }
 89     //直到两个点处于一条链上
 90     if(dep[x]>dep[y])swap(x,y); //把x点深度更深的那个点
 91     if(x!=y)
 92         ans^=query(id[x]+1,id[y],1); //这时再加上此时两个点的区间和即可
 93     return ans;
 94 }
 95 void init()
 96 {
 97     memset(head,-1,sizeof(head));
 98     num=-1;
 99 }
100 int main(){
101     init();
102     int n;
103     scanf("%d",&n);
104     for(int i=1;i<n;i++){
105         int u,v,w;
106         scanf("%d%d%d",&u,&v,&w);
107         add(u,v,w);
108     }
109     dfs1(1,0,1);
110     dfs2(1,1);
111     build(1,n,1);
112     int T;
113     scanf("%d",&T);
114     while(T--){
115         int u,v;
116         scanf("%d%d",&u,&v);
117         printf("%d\n",qRange(u,v));
118     }
119     return 0;
120 }

 

posted @ 2020-02-24 10:59  古比  阅读(188)  评论(0编辑  收藏  举报