1. 程式人生 > >2017瀋陽網路賽G XOR 分塊(分類討論sqrt)

2017瀋陽網路賽G XOR 分塊(分類討論sqrt)

題意:一棵樹,點權,Q次詢問,A---B路徑上每K個點的異或和

連結:點選開啟連結

思路:分類討論,k小於200,類似dp的預處理,在求lca的過程中可以求出來,k大於200,直接暴力跳,最多跳sqrtn步,其中還帶個log的倍增。1200ms AC。。

PS  :場上手殘。。。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
const int DEG = 20;
int root;
struct Edge{
    int to,next;
} edge[MAXN*2];
int head[MAXN],tot;
void addedge(int u,int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void init(){
    tot = 0;
    memset(head,-1,sizeof(head));
}
int fa[MAXN][DEG];//fa[i][j]表示結點i的第2^j個祖先
int deg[MAXN];//深度陣列
int w[MAXN];
int dp[MAXN][205];
int fa2[MAXN][205];
void BFS(int root){
    queue<int>que;
    deg[root] = 0;
    fa[root][0] = root;
    que.push(root);
    while(!que.empty()){
        int tmp = que.front();
        que.pop();
        for(int i = 1; i < DEG; i++)
            fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
        fa2[tmp][0]=tmp;
        for(int i = 1; i <= 200; i++)
            fa2[tmp][i]=fa2[fa[tmp][0]][i-1];
        for(int i = 1; i <= 200; i++)
            dp[tmp][i]=dp[fa2[tmp][i]][i]^w[tmp];
        for(int i = head[tmp]; i != -1; i = edge[i].next){
            int v = edge[i].to;
            if(v == fa[tmp][0])continue;
            deg[v] = deg[tmp] + 1;
            fa[v][0] = tmp;
            que.push(v);
        }
    }
}
int LCA(int u,int v){
    if(deg[u] > deg[v])swap(u,v);
    int hu = deg[u], hv = deg[v];
    int tu = u, tv = v;
    for(int det = hv-hu, i = 0; det ; det>>=1, i++)
        if(det&1)tv = fa[tv][i];
    if(tu == tv)return tu;
    for(int i = DEG-1; i >= 0; i--){
        if(fa[tu][i] == fa[tv][i])continue;
        tu = fa[tu][i];
        tv = fa[tv][i];
    }
    return fa[tu][0];
}
bool flag[MAXN];

int go(int x,int step){
    for(int det = step, i = 0; det ; det>>=1, i++)
        if(det&1){
            x = fa[x][i];
            if(x==root) break;
        }
    return x;
}

int Sum(int x,int step){
    int ret=w[x];
    while(x!=root){
        x=go(x,step);
        ret^=w[x];
    }
    return ret;
}


int main(){
    int T,N,Q;
    int u,v,k;
    while(scanf("%d%d",&N,&Q)!=EOF){
        init();
        memset(dp,0,sizeof(dp));
        memset(w,0,sizeof(w));
        for(int i = 1; i < N; i++){
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=1;i<=N;i++) scanf("%d",&w[i]);
        for(int i=1;i<=N;i++) addedge(N+i,N+i-1),addedge(N+i-1,N+i);
        root=N+N;
        BFS(root);
        for(int i=0;i<Q;i++){
            scanf("%d%d%d",&u,&v,&k);
            int ans=0;
            if(u==v){
                ans=w[u];
            }
            else if(k<=200){
                int lca=LCA(u,v);
                int lab=deg[u]+deg[v]-2*deg[lca];
                int lalca=deg[u]-deg[lca];
                int yu1=lalca%k,yu2=k-yu1,yu3=lab%k;
                ans=dp[u][k]^dp[go(lca,yu2)][k]^dp[go(v,yu3)][k]^dp[go(lca,yu1)][k];
            }
            else{
                int lca=LCA(u,v);
                int lab=deg[u]+deg[v]-2*deg[lca];
                int lalca=deg[u]-deg[lca];
                int yu1=lalca%k,yu2=k-yu1,yu3=lab%k;
                ans=Sum(u,k)^Sum(go(lca,yu2),k)^Sum(go(v,yu3),k)^Sum(go(lca,yu1),k);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}