樹鏈剖分【p4116】Qtree3 - Query on a tree
阿新 • • 發佈:2018-10-31
Description
給出N個點的一棵樹(N-1條邊),節點有白有黑,初始全為白
有兩種操作:
0 i : 改變某點的顏色(原來是黑的變白,原來是白的變黑)
1 v : 詢問1到v的路徑上的第一個黑點,若無,輸出-1
Input
第一行 N,Q,表示N個點和Q個操作
第二行到第N行N-1條無向邊
再之後Q行,每行一個操作"0 i" 或者"1 v" (1 ≤ i, v ≤ N).
Output
對每個1 v操作輸出結果
很明顯.樹上區間問題,我們考慮樹鏈剖分.
單點修改,我們就直接修改即可.
而對於這個詢問操作,則有一些思維難度.(不是很難的
首先,遇到一個線段樹上的節點.我們需要考慮其是否有黑點,如果有的話,我們優先選擇左子樹中的黑點,(可以保證是從\(1\)到\(v\)的第一個黑點)
具體實現起來不難,注意陣列要開夠.
複雜度\(O(能過)\)
程式碼
#include<cstdio> #include<cctype> #include<cstring> #define R register #define N 200008 using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int n,m,head[N],tot; struct cod{int u,v;}edge[N<<2]; inline void add(int x,int y) { edge[++tot].u=head[x]; edge[tot].v=y; head[x]=tot; } int f[N],depth[N],size[N],son[N]; void dfs1(int u,int fa) { f[u]=fa;depth[u]=depth[fa]+1;size[u]=1; for(R int i=head[u];i;i=edge[i].u) { if(edge[i].v==fa)continue; dfs1(edge[i].v,u); size[u]+=size[edge[i].v]; if(son[u]==-1 or size[son[u]]<size[edge[i].v]) son[u]=edge[i].v; } } int idx,dfn[N],fdfn[N],top[N]; void dfs2(int u,int t) { dfn[u]=++idx;fdfn[idx]=u;top[u]=t; if(son[u]==-1)return; dfs2(son[u],t); for(R int i=head[u];i;i=edge[i].u) { if(dfn[edge[i].v])continue; dfs2(edge[i].v,edge[i].v); } } bool tr[N<<2]; int pos[N<<2]; #define ls o<<1 #define rs o<<1|1 inline void up(int o) { tr[o]=tr[ls] | tr[rs]; pos[o]= tr[ls] ? pos[ls]:(tr[rs]? pos[rs]:-1); } void change(int o,int l,int r,int poss) { if(l==r){tr[o]^=1;pos[o]=tr[o] ? fdfn[l]:-1; return;} int mid=(l+r)>>1; if(poss<=mid)change(ls,l,mid,poss); else change(rs,mid+1,r,poss); up(o); } int query(int o,int l,int r,int x,int y) { if(l>y or r<x)return -1; if(x<=l and y>=r)return pos[o]; int mid=(l+r)>>1,le,ri; le=query(ls,l,mid,x,y),ri=query(rs,mid+1,r,x,y); return le==-1 ? ri:le; } inline int tquery(int x) { int ans=-1,p,fx=top[x]; while(fx!=1) { p=query(1,1,n,dfn[fx],dfn[x]); ans=(p==-1? ans:p); x=f[fx];fx=top[x]; } p=query(1,1,n,1,dfn[x]); ans=(p==-1 ? ans : p); return ans; } int main() { in(n),in(m); memset(son,-1,sizeof son); memset(pos,-1,sizeof pos); for(R int i=1,x,y;i<n;i++) { in(x),in(y); add(x,y);add(y,x); } dfs1(1,0); dfs2(1,1); for(R int opt,x;m;m--) { in(opt);in(x); if(opt==0) change(1,1,n,dfn[x]); else printf("%d\n",tquery(x)); } }