BZOJ 4129 Haruna’s Breakfast 树上莫队
树上莫队求mex,关键点:I.树上莫队(废话)II.树状数组+二分 log^2 求mex
树上莫队的时间复杂度一定是O(n1.5)的证明 I.右端点dfs序 II.左端点均摊(卡的话是一个近似二次函数的东西,会随着卡你的地方增多而卡的程度减小)
#include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #define N 18 #define MAXN 51000 using namespace std; int pos[MAXN+10],id[MAXN+10],a[MAXN+10],b[MAXN+10],len,n,m,f[MAXN+10][N+10],size,d[MAXN+10],had[MAXN+10]; bool belong[MAXN+10]; struct Q { int l,r,time,ans,id; }q[MAXN+10]; struct T { int a,b,pos; }t[MAXN+10]; struct Tree { int to,next; }c[MAXN<<2]; int head[MAXN+10],sz,cause; inline void update(int x,int i) { if(x==0)return; while(x<MAXN) { b[x]+=i; x+=x&(-x); } } inline int sum(int x) { int ret=0; while(x>0) { ret+=b[x]; x-=x&(-x); } return ret; } inline void add(int x,int y) { c[++sz].to=y; c[sz].next=head[x]; head[x]=sz; c[++sz].to=x; c[sz].next=head[y]; head[y]=sz; } int l,r,now; void dfs(int x) { id[x]=++cause; d[x]=d[f[x][0]]+1; for(int i=1;i<N;i++) f[x][i]=f[f[x][i-1]][i-1]; for(int i=head[x];i;i=c[i].next) if(c[i].to!=f[x][0]) { f[c[i].to][0]=x; dfs(c[i].to); } } int comp(const Q aa,const Q bb) { return pos[id[aa.l]]<pos[id[bb.l]]||(pos[id[aa.l]]==pos[id[bb.l]]&&id[aa.r]<id[bb.r]); } int end_comp(const Q aa,const Q bb) { return aa.id<bb.id; } void pre() { scanf("%d%d",&n,&m); len=(int)(sqrt(n+0.5)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); pos[i]=(i-1)/len+1; } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } dfs(1); for(int i=1;i<=m;i++) { int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if(opt==0) { now++; t[now].a=a[x]; t[now].b=y; t[now].pos=x; a[x]=y; } else { q[++size].l=x; q[size].r=y; q[size].time=now; q[size].id=size; } } sort(q+1,q+size+1,comp); l=r=1; belong[1]=1; if(a[1]<MAXN)had[a[1]]=1; if(a[1]>=MAXN||a[1]==0)return; update(a[1],1); } int Lca(int x,int y) { if(d[x]<d[y]) x^=y^=x^=y; int k=d[x]-d[y]; for(int i=0;i<N;i++) if((1<<i)&k) x=f[x][i]; if(x==y) { return x; } for(int i=N-1;i>=0;i--) if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } inline void via(int x) { belong[id[x]]^=1; if(a[x]>=MAXN)return; if(belong[id[x]]) { had[a[x]]++; if(a[x]==0)return; if(had[a[x]]==1) update(a[x],1); } else { had[a[x]]--; if(a[x]==0)return; if(had[a[x]]==0) update(a[x],-1); } } inline void come(int x) { if(!x)return; a[t[x].pos]=t[x].b; if(belong[id[t[x].pos]]) { if(t[x].a<MAXN) { had[t[x].a]--; if(t[x].a!=0&&had[t[x].a]==0) update(t[x].a,-1); } if(t[x].b<MAXN) { had[t[x].b]++; if(t[x].b!=0&&had[t[x].b]==1) update(t[x].b,1); } } } inline void go(int x) { if(!x)return; a[t[x].pos]=t[x].a; if(belong[id[t[x].pos]]) { if(t[x].b<MAXN) { had[t[x].b]--; if(t[x].b!=0&&had[t[x].b]==0) update(t[x].b,-1); } if(t[x].a<MAXN) { had[t[x].a]++; if(t[x].a!=0&&had[t[x].a]==1) update(t[x].a,1); } } } inline int answer() { if(had[0]==0)return 0; int z=1,y=MAXN-1,ans=0; while(z<=y) { int mid=(z+y)>>1; int ques=sum(mid); if(ques<mid) ans=mid,y=mid-1; else z=mid+1; } return ans; } void work() { for(int i=1;i<=size;i++) { while(now<q[i].time)come(++now); while(now>q[i].time)go(now--); int lca1=Lca(q[i].l,q[i].r); int lca2=Lca(l,r); int lca3=Lca(q[i].l,l); int lca4=Lca(q[i].r,r); while(l!=lca3) { via(l); l=f[l][0]; } l=q[i].l; while(l!=lca3) { via(l); l=f[l][0]; } l=q[i].l; while(r!=lca4) { via(r); r=f[r][0]; } r=q[i].r; while(r!=lca4) { via(r); r=f[r][0]; } r=q[i].r; if(lca1!=lca2) { via(lca1); via(lca2); } q[i].ans=answer(); } } void print() { sort(q+1,q+size+1,end_comp); for(int i=1;i<=size;i++) printf("%d\n",q[i].ans); } int main() { pre(); work(); print(); return 0; }
苟利国家生死以, 岂因祸福避趋之。