Evanyou Blog 彩带

P4592 [TJOI2018]异或

题目描述

现在有一颗以1为根节点的由n个节点组成的树,树上每个节点上都有一个权值vi。现在有Q次操作,操作如下:

  • y:查询节点x的子树中与y异或结果的最大值
  • z:查询路径x到y上点与z异或结果最大值

输入输出格式

输入格式:

 

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

第二行是n个数字用空格隔开,第i个数字vi表示点i上的权值

接下来n1行,每行两个数,x,y,表示节点x与y之间有边

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

 

输出格式:

 

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

 

输入输出样例

输入样例#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%的数据,有1<n,Q100

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

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

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

对于100%的数据,有查询1中的y230,查询2中的z230

 

Solution:

  本题可持久化trie树。

  最大异或和都会吧,本题不过是把操作放到了树上罢了。

  对于操作$1$:在子树中选取某一信息,明摆着dfs序弄出来,用可持久化trie树维护一下dfs序的节点权值,询问只要在子树的dfs序中贪心就好了。

  对于操作$2$:查询树上路径,那么就跑lca嘛,用可持久化trie树自上而下维护根节点到每个节点的链的节点权值,对于询问$x,y$,在$s_x-s_{lca(x,y)-1}+s_y-s_{lca(x,y)}$的节点信息中贪心就好了。

代码:

/*Code by 520 -- 9.29*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=100005;
int n,m,val[N],rt1[N],rt2[N],cnt1,cnt2;
int fa[N][21],dep[N],to[N<<1],net[N<<1],h[N],ec;
int inc[N],ouc[N],ppx;
struct node{
    int son[2],tot;    
}t1[N*80],t2[N*80];

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;    
}

il void add(int u,int v){to[++ec]=v,net[ec]=h[u],h[u]=ec;}

void ins1(int &rt,int lst,int d,int v){
    t1[rt=++cnt1]=t1[lst],t1[rt].tot++;
    if(d<0) return;
    int p=v&(1<<d)?1:0;
    ins1(t1[rt].son[p],t1[lst].son[p],d-1,v);
}

int query1(int l,int r,int d,int v,int ans){
    if(d<0) return ans;
    int p=v&(1<<d)?1:0,ls=t1[t1[l].son[p^1]].tot,rs=t1[t1[r].son[p^1]].tot;
    if(rs-ls) return query1(t1[l].son[p^1],t1[r].son[p^1],d-1,v,ans|(1<<d));
    return query1(t1[l].son[p],t1[r].son[p],d-1,v,ans);    
}

void ins2(int &rt,int lst,int d,int v){
    t2[rt=++cnt2]=t2[lst],t2[rt].tot++;
    if(d<0) return;
    int p=v&(1<<d)?1:0;
    ins2(t2[rt].son[p],t2[lst].son[p],d-1,v);
}

int query2(int lx,int rx,int ly,int ry,int d,int v,int ans){
    if(d<0) return ans;
    int p=v&(1<<d)?1:0,ls=t2[t2[lx].son[p^1]].tot+t2[t2[ly].son[p^1]].tot,rs=t2[t2[rx].son[p^1]].tot+t2[t2[ry].son[p^1]].tot;
    if(rs-ls) return query2(t2[lx].son[p^1],t2[rx].son[p^1],t2[ly].son[p^1],t2[ry].son[p^1],d-1,v,ans|(1<<d));
    return query2(t2[lx].son[p],t2[rx].son[p],t2[ly].son[p],t2[ry].son[p],d-1,v,ans);
}

void dfs(int u){
    inc[u]=++ppx;
    ins1(rt1[inc[u]],rt1[inc[u]-1],30,val[u]);
    ins2(rt2[u],rt2[u],30,val[u]);
    for(RE int i=h[u];i;i=net[i])
        if(to[i]!=fa[u][0]){
            fa[to[i]][0]=u,dep[to[i]]=dep[u]+1,rt2[to[i]]=rt2[u];
            dfs(to[i]);    
        }
    ouc[u]=ppx;
}

il int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    int dd=dep[x]-dep[y];
    For(i,0,20) if(dd&(1<<i)) x=fa[x][i];
    if(x==y) return x;
    Bor(i,0,20) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main(){
    n=gi(),m=gi();
    For(i,1,n) val[i]=gi();
    int opt,x,y,z,tp;
    For(i,1,n-1) x=gi(),y=gi(),add(x,y),add(y,x);
    dfs(1);
    For(j,1,20) For(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
    while(m--){
        opt=gi(),x=gi(),y=gi();
        if(opt==1) printf("%d\n",query1(rt1[inc[x]-1],rt1[ouc[x]],30,y,0));
        else {
            z=gi(),tp=lca(x,y);
            printf("%d\n",query2(rt2[fa[tp][0]],rt2[x],rt2[tp],rt2[y],30,z,0));
        }
    }
    return 0;    
}

 

posted @ 2018-09-30 09:07  five20  阅读(242)  评论(0编辑  收藏  举报
Live2D