2017 ACM-ICPC 亚洲区(西安赛区)网络赛 G. Xor

来源:互联网 发布:做个文明中国人 知乎 编辑:程序博客网 时间:2024/06/05 16:12

There is a tree with nn nodes. For each node, there is an integer value a_iai, (1 \le a_i \le 1,000,000,0001ai1,000,000,000 for 1 \le i \le n1in). There is qq queries which are described as follow: Assume the value on the path from node aa to node bb is t_0, t_1, \cdots t_mt0,t1,tm. You are supposed to calculate t_0t0 xor t_ktk xor t_{2k}t2k xor ... xor t_{pk}tpk (pk \le m)(pkm).

Input Format

There are multi datasets. (\sum n \le 50,000, \sum q \le 500,000)(n50,000,q500,000).

For each dataset: In the first n-1n1 lines, there are two integers u,vu,v, indicates there is an edge connect node uuand node vv.

In the next nn lines, There is an integer a_iai (1 \le a_i \le 1,000,000,0001ai1,000,000,000).

In the next qq lines, There is three integers a,ba,b and kk. (1 \le a,b,k \le n1a,b,kn).

Output Format

For each query, output an integer in one line, without any additional space.

样例输入

5 61 54 12 13 2192608175 5 11 3 23 2 15 4 23 4 41 4 5

样例输出

17192625019

题意:给一棵树,然后每个点都有一个权值,另给q个查询,每个查询包括a,b,k三个值,表示求从a到b的路径上每相隔k个点的权值的异或值,起点从a开始;

思路:当时网赛的时候没做出来,瑞神做的这个题,当时弱弱的只贡献了一个暴力程序,结果跑出来的和瑞神的一摸一样但就是wa;赛后看题解补得,这个题首先暴不行,但是有没有足够的空间和时间进行预处理,而且也无法保存所有状态以至于在log内就可以进行求解,所以综合一下,这个题就只能优雅的暴了,如何优雅?既然k会有1的情况出现,好,那我们就先预处理出1来,但还会有2,2的复杂度也很爆炸,好我们再预处理出2来,那3呢?好继续预处理,怎么停呢?预处理 根号n个,跟下50000为223,我们完全有时间和空间进行预处理。已经处理了根号n之后,剩下的复杂度暴力也是可以承受的,所以就是预处理根号n以下的,然后剩下的暴力;这里的技巧就是寻找从某一点开始相隔k个点的点,这里采用的是倍增的思想,用rmq预处理一下父节点,然后进行二分似的倍增往上跳即可;我这里LCA用的树剖,树上区间操作树剖永远的王道!

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;const int maxed=50000+10;struct E{    int v,bef;}e[maxed*2];int n,m,ans,head[maxed],p[maxed];int top[maxed],son[maxed],size_[maxed],d[maxed];int f[maxed][20],sxor_[maxed][255];int main(){    //freopen("shuJu.txt","w",stdout);    void add_(int,int);    void slove_1(int,int);    void slove_2(int,int);    int lca(int,int);    int find_(int,int);    while(scanf("%d%d",&n,&m)!=EOF){        ans=1;        memset(head,-1,sizeof(head));        int a,b,c;        for(int i=1;i<=n-1;i++){            scanf("%d%d",&a,&b);            add_(a,b);            add_(b,a);        }        memset(f,0,sizeof(f));        for(int i=1;i<=n;i++){            scanf("%d",&p[i]);            son[i]=0;            if (i == 1)                f[i][0] = 0;            else                f[i][0] = i;        }        d[0] = 0;        memset(sxor_,0,sizeof(sxor_));        slove_1(1,1);        slove_2(1,1);        for(int i=1;i<=20;i++)            for(int j=1;j<=n;j++){                int r=f[j][i-1];                if(r==0)                    continue;                f[j][i]=f[r][i-1];            }        int len=(int)sqrt(n);        while(m--){            scanf("%d%d%d",&a,&b,&c);            int wa=lca(a,b);            if(c<=len){                int answer=sxor_[a][c];                int k=c-(d[a]-d[wa])%c;                int kk=find_(wa,k);                answer^=sxor_[kk][c];                if (d[b] - d[wa] - k >= 0 && b != wa) {                    kk = (d[b] - d[wa] - k)%c;                    int r = find_(b, kk);                    answer ^= sxor_[r][c];                    kk = (d[a] - d[wa])%c;                    k = find_(wa, kk);                    answer ^= sxor_[k][c];                }                printf("%d\n", answer);            }            else{                int answer = 0, l = a, r = b;                while (d[l] >= d[wa]){                    answer ^= p[l];                    l = find_(l, c);                }                if (d[r] - d[wa] - (c - (d[a] - d[wa])%c) >= 0 && b != wa) {                    int k = (d[r] - d[wa] - (c - (d[a] - d[wa])%c))%c;                    r = find_(r, k);                    while (d[r] > d[wa]) {                        answer ^= p[r];                        r = find_(r, c);                    }                }                printf("%d\n", answer);            }        }    }    return 0;}void add_(int x,int y){    e[ans].v=y;    e[ans].bef=head[x];    head[x]=ans++;}void slove_1(int u,int dep){    size_[u]=1;    d[u]=dep;    int now=u,step=0;    while(step<255){        sxor_[u][step]=p[u]^sxor_[now][step];        now = f[now][0];        step++;    }    for(int i=head[u];i!=-1;i=e[i].bef){        int v=e[i].v;        if (f[u][0] == v)            continue;        f[v][0] = u;        slove_1(v,dep+1);        size_[u]+=size_[v];        if(!son[u]||size_[son[u]]<size_[v])            son[u]=v;    }}void slove_2(int u,int fa){    top[u]=fa;    if(son[u])        slove_2(son[u],fa);    for(int i=head[u];i!=-1;i=e[i].bef){        int v=e[i].v;        if (f[u][0] == v || son[u] == v)            continue;        slove_2(v,v);    }}int lca(int a,int b){    int f1=top[a],f2=top[b],l=a,r=b;    while(f1!=f2){        if(d[f1]<d[f2]){            swap(f1,f2);            swap(l,r);        }        l = f[f1][0];        f1=top[l];    }    if(d[l]>d[r])        swap(l,r);    return l;}int find_(int a,int x){    int s=0;    while(x){        if(x&1)            a=f[a][s];        x>>=1;        s++;    }    return a;}


阅读全文
0 0