洛谷 P4592 [TJOI2018]異或 解題報告
阿新 • • 發佈:2018-11-03
P4592 [TJOI2018]異或
題目描述
現在有一顆以\(1\)為根節點的由\(n\)個節點組成的樹,樹上每個節點上都有一個權值\(v_i\)。現在有\(Q\)次操作,操作如下:
1 x y
:查詢節點\(x\)的子樹中與\(y\)異或結果的最大值2 x y
:查詢路徑\(x\)到\(y\)上點與\(z\)異或結果最大值
輸入輸出格式
輸入格式:
第一行是兩個數字\(n,Q\);
第二行是\(n\)個數字用空格隔開,第\(i\)個數字\(v_i\)表示點\(i\)上的權值
接下來\(n-1\)行,每行兩個數,\(x,y\),表示節點\(x\)與\(y\)之間有邊
接下來\(Q\)行,每一行為一個查詢,格式如上所述.
輸出格式:
對於每一個查詢,輸出一行,表示滿足條件的最大值。
說明
對於\(10\%\)的資料,有\(1<n,Q\leq100\)
對於\(20\%\)的資料,有\(1<n,Q\leq1000\)
對於\(40\%\)的資料,有\(1<n,Q\leq10000\)
對於\(100\%\)的資料,有\(1<n,Q\leq100000\)
對於\(100\%\)的資料,有查詢\(1\)中的\(y\leq2^{30}\),查詢\(2\)中的\(z\leq2^{30}\)。
區間異或最大值可以用可持久化字典樹實現。
這個題建對DFS序建一顆,對自根向下的鏈建,分別處理兩種詢問就可以了。
Code:
#include <cstdio> #include <cctype> const int N=1e5+10; int read() { int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) {x=x*10+c-'0';c=getchar();} return x; } int max(int x,int y){return x>y?x:y;} #define ls ch[now][0] #define rs ch[now][1] #define rep(i,a,b) for(int i=a;i<=b;i++) int head[N],to[N<<1],Next[N<<1],cnt; void add(int u,int v) { to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt; } int poi[N],n,Q; namespace work1//子樹 { int ch[N*32][2],mx[N*32],tot,dfn[N],low[N],ha[N],dfsclock,root[N]; void dfs(int now,int fa) { dfn[now]=++dfsclock; ha[dfsclock]=now; for(int i=head[now];i;i=Next[i]) if(to[i]!=fa) dfs(to[i],now); low[now]=dfsclock; } void Insert(int las,int &now,int dep,int id) { if(!now) now=++tot; if(dep<0){mx[now]=id;return;} int bit=poi[ha[id]]>>dep&1; Insert(ch[las][bit],ch[now][bit],dep-1,id); ch[now][bit^1]=ch[las][bit^1]; mx[now]=max(mx[ls],mx[rs]); } void init() { dfs(1,0); rep(i,1,n) Insert(root[i-1],root[i],30,i); } int query(int now,int les,int dep,int x) { if(dep<0) return x^poi[ha[mx[now]]]; int bit=x>>dep&1; if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,dep-1,x); return query(ch[now][bit],les,dep-1,x); } void work() { int x=read(),y=read(); printf("%d\n",query(root[low[x]],dfn[x],30,y)); } } namespace work2 { int f[N][20],ch[N*32][2],mx[N*32],root[N],dep[N],en[N*32],tot,tmp; void swap(int &x,int &y){tmp=x,x=y,y=tmp;} void Insert(int las,int &now,int de,int id) { if(!now) now=++tot; if(de<0){mx[now]=dep[id],en[now]=id;return;} int bit=poi[id]>>de&1; Insert(ch[las][bit],ch[now][bit],de-1,id); ch[now][bit^1]=ch[las][bit^1]; mx[now]=max(mx[ls],mx[rs]); } void dfs(int now) { for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1]; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v==f[now][0]) continue; dep[v]=dep[now]+1; f[v][0]=now; Insert(root[now],root[v],30,v); dfs(v); } } void init() { dep[1]=1; Insert(0,root[1],30,1); dfs(1); } int LCA(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=18;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=18;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int query(int now,int les,int de,int x) { if(de<0) return poi[en[now]]^x; int bit=x>>de&1; if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,de-1,x); return query(ch[now][bit],les,de-1,x); } void work() { int x=read(),y=read(),z=read(),lca=LCA(x,y); printf("%d\n",max(query(root[x],dep[lca],30,z),query(root[y],dep[lca],30,z))); } } int main() { n=read(),Q=read(); rep(i,1,n) scanf("%d",poi+i); for(int u,v,i=1;i<n;i++) u=read(),v=read(),add(u,v),add(v,u); work1::init(); work2::init(); rep(i,1,Q) { if(read()==1) work1::work(); else work2::work(); } return 0; }
2018.11.3