P4592 [TJOI2018]异或

链接:https://www.luogu.org/problemnew/show/P4592

题目描述

现在有一颗以 11 为根节点的由 nn 个节点组成的树,树上每个节点上都有一个权值 v_ivi 。现在有 QQ 次操作,操作如下:

  • 1\;x\;y1xy :查询节点 xx 的子树中与 yy 异或结果的最大值
  • 2\;x\;y\;z2xyz :查询路径 xx 到 yy 上点与 zz 异或结果最大值

输入输出格式

输入格式:

第一行是两个数字 n,Qn,Q ;

第二行是 nn 个数字用空格隔开,第 ii 个数字 v_ivi 表示点 ii 上的权值

接下来 n-1n1 行,每行两个数, x,yx,y ,表示节点 xx 与 yy 之间有边

接下来 QQ 行,每一行为一个查询,格式如上所述.

输出格式:

对于每一个查询,输出一行,表示满足条件的最大值。

输入输出样例

输入样例#1:  复制
7 5
1 3 5 7 9 2 4
1 2
1 3
2 4
2 5
3 6
3 7
1 3 5
2 4 6 3
1 5 5
2 5 7 2
1 1 9
输出样例#1:  复制
7
6
12
11
14

说明

对于 10\%10% 的数据,有 1<n,,Q100

对于 20\%20% 的数据,有 1<n,,Q1000

对于 40\%40% 的数据,有 1<n,,Q10000

对于 100\%100% 的数据,有 1<n,Q100000

对于 100\%100% 的数据,有查询 11 中的y2^30 ,查询 22 中的 z2^30 。

题解:贪心+可持续化Trie树; 对于子树查询用dfn序; 对于链上查询, 我们对每个点建一个他到根节点的Trie树,然后跑lca,又变成了序列上的查询;

好久不写倍增都错了

#include<bits/stdc++.h>
using namespace std;
const int M = 100005, Trie_M = 1e7;
#define ll long long
#define For(a, b, c) for(int a = b; a <= c; a++)
#define ex(i, u) for(int i = h[u]; i; i = G[i].nxt)

int dep[M], out[M], dfn[M], val[M], nval[M], root[M], h[M], anc[M][20], tot, idx, cnt;
ll bin[35];
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
    return x*=f;
}
struct edge{ int v, nxt;}G[M << 1];
void add(int u, int v){G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot;}

struct Trie{
    int root[M];
    struct Tree{
        int ch[2], ptr[2];
    }tree[Trie_M];
    
    void ins(int f, int &now, int x, int c = 0){
        now = ++cnt;
        int res = now;
        tree[res] = tree[f];
        
        for(int i = 31; i >= 0; i--){
            int d = (x & bin[i]) ? 1 : 0;
            tree[res].ch[d]++;
            int p = ++cnt;
            tree[res].ptr[d] = p;
            f = tree[f].ptr[d];
            tree[p] = tree[f];
            res = tree[res].ptr[d];    
            //printf("%d ", d);        
        }
        //printf("\n");
    }
    
    
    ll query(int lf, int rg, int x){
        ll ret = 0;
        for(int i = 31; i >= 0; i--){
            int d = (x & bin[i]) ? 1 : 0;
            if(tree[rg].ch[d^1] - tree[lf].ch[d^1]){
                lf = tree[lf].ptr[d^1], rg = tree[rg].ptr[d^1];
                ret += bin[i];
            }    
            else lf = tree[lf].ptr[d], rg = tree[rg].ptr[d];
        }
        return ret;    
    }
    
}xuelie, zishu;


void dfs(int u, int f){
    dfn[u] = ++idx;
    nval[idx] = val[u];
    dep[u] = dep[f] + 1;
    
    anc[u][0] = f;
    For(p, 1, 19)
        anc[u][p] = anc[anc[u][p - 1]][p - 1];
    
    xuelie.ins(xuelie.root[f], xuelie.root[u], val[u]);
    
    ex(i, u){
        int v = G[i].v;
        if(v == f)continue;
        dfs(v, u);
    }
    out[u] = idx;
}

int find_lca(int u, int v){
    if(dep[u] < dep[v])swap(u, v);
    int t = dep[u] - dep[v];
    for(int p = 0; t; t >>= 1, p++)
        if(t & 1)u = anc[u][p];
    if(u == v)return u;
    for(int p = 19; p >= 0; p--)
        if(anc[u][p] != anc[v][p])
            u = anc[u][p], v = anc[v][p];
    return anc[u][0];
}




int main(){
    //freopen("data.out","r",stdin);
    //freopen("my.out","w",stdout);
    int n, Q;
    bin[0] = 1;
    For(i, 1, 32) bin[i] = bin[i - 1] << 1;
    
    scanf("%d%d", &n, &Q);
    For(i, 1, n) val[i] = read();
    For(i, 1, n-1){
        int u = read(), v = read();
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    For(i, 1, n) zishu.ins(zishu.root[i - 1], zishu.root[i], nval[i]);
    
    int opt, x, y, z;
    For(i, 1, Q){
        opt = read(), x = read(), y = read();
        if(opt == 1){
            printf("%lld\n", zishu.query(zishu.root[dfn[x] - 1], zishu.root[out[x]], y));
        }
        else {
            int z = read();
            int flca = anc[find_lca(x, y)][0];
            //printf("%d      ", flca);
            ll ans = max(xuelie.query(xuelie.root[flca], xuelie.root[x], z), xuelie.query(xuelie.root[flca], xuelie.root[y], z));
            printf("%lld\n",ans);
        }
    }
    
}

/*
7 5
1 3 5 7 9 2 4
1 2
1 3
2 4
2 5
3 6
3 7
1 3 5
2 4 6 3
1 5 5
2 5 7 2
1 1 9
*/
View Code

猜你喜欢

转载自www.cnblogs.com/EdSheeran/p/9470072.html