码迷,mamicode.com
首页 > 其他好文 > 详细

BestCoder #45 1003 Dylans loves tree

时间:2015-06-22 06:28:45      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:dfs序   线段树   

problem


题意

  • 给定一棵树,并给定在这棵树上的两种操作。一种操作是改变一个节点的权值,另外一个操作是对两个节点之间的路径上的权值进行统计,如果每个权值出现的次数都是偶数,输出-1,否则输出出现次数为奇数的权值(保证只有一个)

思路

  • 这题是一个DFS序的模板题。首先想到,我们获得这棵树的DFS序,对于这个序列,我们可以去维护区间的异或和。由于是单点修改区间查询,可以用树状数组也可以直接写线段树。然后对于每个询问,我们查询出每个点到根的异或和(这里直接用DFS序中到根节点的异或和即可,因为如果一个结点不在其到根节点的路径上,其会出现两次,异或和为0),然后求出这两个结点的LCA,再异或LCA的权值。注意这个地方,如果一个结点权值为0,会出错。所以这里要进行处理(把权值都加1,输出答案的时候减1)。LCA用倍增法、Tarjan、RMQ都可以。
  • 这题HDU略坑,交G++一直爆栈。然而没必要去管这个。。交C++就过了。

AC代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = 110000;
int cnt,head[MAXN],dep[MAXN],p[MAXN][20],tot;
int st[MAXN],ed[MAXN];
int sum[MAXN<<3];
int n,q;
void update(int pos,int c,int l,int r,int rt){
    if(l == r){
        sum[rt] = c;
        return;
    }
    int m = (l+r)>>1;
    if(pos <= m)update(pos,c,lson);
    else update(pos,c,rson);
    sum[rt] = sum[rt<<1] ^ sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt){
    if(l>=L && R>=r){
        return sum[rt];
    }
    int ret = 0;
    int m = (l+r)>>1;
    if(L <= m)ret ^= query(L,R,lson);
    if(R > m)ret ^= query(L,R,rson);
    return ret;
}
struct Edge{
    int u,v;
    int next;
}e[MAXN<<1];
void addedge(int u,int v){
    e[cnt].u = u,e[cnt].v = v,e[cnt].next = head[u],head[u] = cnt++;
    e[cnt].u = v,e[cnt].v = u,e[cnt].next = head[v],head[v] = cnt++;
}
void dfs(int u){
    st[u] = tot++;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v = e[i].v;
        if(!dep[v]){
            dep[v] = dep[u] + 1;
            p[v][0] = u;
            dfs(v);
        }
    }
    ed[u] = tot++;
}
void init(){
    cnt = 0;
    tot = 1;
    memset(head,-1,sizeof(head));
    memset(p,-1,sizeof(p));
    memset(dep,0,sizeof(dep));
}
int LCA(int a,int b){
    if(dep[a]<dep[b])swap(a,b);
    int i;
    for(i = 0;(1<<i)<=dep[a];i++);
    i--;
    for(int j=i;j>=0;j--)
        if(dep[a]-(1<<j)>=dep[b])
            a = p[a][j];
    if(a == b)return a;
    for(int j=i;j>=0;j--){
        if(p[a][j]!=-1 && p[a][j] != p[b][j]){
            a = p[a][j];
            b = p[b][j];
        }
    }
    return p[a][0];
}
int u,v;
int main()
{
    int T;
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&q);
        init();
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
        }
        dep[1] = 1;
        dfs(1);
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i<=n;i++)
                if(p[i][j-1] != -1)
                    p[i][j] = p[p[i][j-1]][j-1];
        tot--;
        memset(sum,0,sizeof(sum));
        //for(int i=1;i<=n;i++)printf("%d ",st[i]);
        //printf("tot : %d\n",tot);
        for(int i=1;i<=n;i++){
            scanf("%d",&u);
            update(st[i],u+1,1,tot,1),update(ed[i],u+1,1,tot,1);
        }
        while(q--){
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op == 0){
                update(st[x],y+1,1,tot,1),update(ed[x],y+1,1,tot,1);
            }else{
                int ansx = query(1,st[x],1,tot,1),ansy = query(1,st[y],1,tot,1);
                int lca = LCA(x,y),anslca =query(st[lca],st[lca],1,tot,1);
                //printf("ansx:%d ansy:%d lca:%d\n",ansx,ansy,lca);
                int ans = ansx ^ ansy ^ anslca;
                if( ans == 0)puts("-1");
                else printf("%d\n",ans-1);
            }
        }
    }
    return 0;
}

BestCoder #45 1003 Dylans loves tree

标签:dfs序   线段树   

原文地址:http://blog.csdn.net/zava_1087/article/details/46586625

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!