BZOJ4129 樹上莫隊+權值分塊
阿新 • • 發佈:2018-12-17
這道題來來回回搞了近十個小時
完全暴露出了自己樹上操作的薄弱
放在區間上面秒殺的題目 放到樹上不知所措
先是離散化寫了三個多小時 一直wa 後來發現離散化的話就不能用分塊做 要用其他資料結構
然後又研究其他資料結構 比如樹狀陣列 還寫炸了 至今不知道炸在哪裡
於是只能回頭搞分塊 終於是調了出來
這題因為是查詢樹上的一條鏈 所以權值大於n的點可以直接丟掉 因為根本達不到那個點
這樣一來問題就簡單很多 也因此不用離散化了
至於其他就是樹上帶修莫隊的基本操作
聽說樹上莫隊還能用尤拉序寫 此處挖坑以後再填
程式碼如下
#include<bits/stdc++.h> using namespace std; const int maxn=5e4+5; struct Edge { int y,next; }edge[2*maxn]; int cnt,cntq,cntc,all,n,m,top,unit,tb; int head[maxn],Be[maxn],st[maxn],fa[maxn][20],deep[maxn],a[maxn],now[maxn],ans[maxn],dfn[maxn]; int num[maxn],siz[maxn],block[maxn]; bool vis[maxn]; struct node { int u,v,t,id; bool operator <(const node &a)const { return Be[u]==Be[a.u]?(Be[v]==Be[a.v]?t<a.t:dfn[v]<dfn[a.v]):Be[u]<Be[a.u]; } }q[maxn]; struct change { int u,New,old; }c[maxn]; void addedge(int x,int y) { edge[++cnt].y=y; edge[cnt].next=head[x]; head[x]=cnt; } void dfs(int x) { dfn[x]=++dfn[0]; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].y; if(v!=fa[x][0]) { fa[v][0]=x; deep[v]=deep[x]+1; dfs(v); } } } int LCA(int x,int y) { if(deep[x]<deep[y]) swap(x,y); for(int i=15;i>=0;i--) { if(fa[x][i]&&deep[fa[x][i]]>=deep[y]) x=fa[x][i]; } if(x==y) return x; for(int i=15;i>=0;i--) { if(fa[x][i]&&fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; } return fa[x][0]; } void work(int x) { if(a[x]>n) { vis[x]^=1; return ; } if(vis[x]) { siz[block[a[x]]]+=(--num[a[x]]==0); } else { siz[block[a[x]]]-=(++num[a[x]]==1); } vis[x]^=1; } void move(int x,int y) { if(deep[x]<deep[y]) swap(x,y); while(deep[x]>deep[y]) { work(x); x=fa[x][0]; } while(x!=y) { work(x); work(y); x=fa[x][0]; y=fa[y][0]; } } int find() { int p=tb+1; for(int i=0;i<=tb;i++) if(siz[i]) { p=i; break; } for(int i=p*tb;i<(p+1)*tb;i++) { if(!num[i]) return i; } } int main() { scanf("%d%d",&n,&m); unit=pow(n,2.0/3); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); now[i]=a[i]; } for(int i=2;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs(1); for(int i=1;i<=n;i++) Be[i]=(dfn[i]+1)/unit; for(int i=1;i<=15;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; tb=sqrt(n+1); for(int i=0;i<=n;i++) { block[i]=i/tb; siz[block[i]]++; } for(int i=1;i<=m;i++) { int op,x,y; scanf("%d%d%d",&op,&x,&y); if(op==0) { c[++cntc]=(change){x,y,now[x]}; now[x]=y; } else { q[++cntq]=(node){x,y,cntc,cntq}; } } sort(q+1,q+cntq+1); int T=0,u=1,v=1; for(int i=1;i<=cntq;i++) { while(T<q[i].t) { T++; if(vis[c[T].u]) { work(c[T].u); a[c[T].u]=c[T].New; work(c[T].u); } else a[c[T].u]=c[T].New; } while(T>q[i].t) { if(vis[c[T].u]) { work(c[T].u); a[c[T].u]=c[T].old; work(c[T].u); } else a[c[T].u]=c[T].old; T--; } if(u!=q[i].u) { move(u,q[i].u),u=q[i].u; } if(v!=q[i].v) { move(v,q[i].v),v=q[i].v; } int tp=LCA(u,v); work(tp); ans[q[i].id]=find(); work(tp); } for(int i=1;i<=cntq;i++) printf("%d\n",ans[i]); return 0; }