BZOJ 3720 gty的妹子树
块状树裸题
块状树:
首先对树进行分块,分出的每一块都是一个连通块
通常的分块的方式如下:
1、父亲所在块不满,分到父亲所在块中
2、父亲所在块满,自己单独开一个块
(貌似有更为优越的分块方式?
注意这是不严格的分块,即每个块的大小不一定都是设定的阈值blo
对于这道题,首先修改和添加直接块内暴力就可以了
对于询问,首先我们对每个块排序,块不完全在询问子树内的单点询问,块完全在询问子树内的块内二分
分块真是骗分利器,但是块状树最大的缺点是容易被菊花树卡住
(貌似修改和添加可以去掉一个log,但是我太弱了,并不想写)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> using namespace std; const int oo=0x7fffffff; const int maxn=200010; int n,m,u,v,f,ans,tot,blo; int pos[maxn],fa[maxn],w[maxn]; int a[10010][510],cnt[10010]; struct Graph{ int h[maxn],next[maxn],to[maxn],sum; void add(int x,int y){++sum;next[sum]=h[x];h[x]=sum;to[sum]=y;} }G,T; void read(int &num){ num=0;char ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } bool cmp(const int &i,const int &j){return i>j;} void check_block(int u){ int k=pos[fa[u]]; if(cnt[k]==blo){ pos[u]=++tot;a[tot][0]=oo; a[tot][++cnt[tot]]=w[u]; T.add(k,tot); }else a[k][++cnt[k]]=w[u],pos[u]=k; for(int i=G.h[u];i;i=G.next[i]){ if(G.to[i]==fa[u])continue; fa[G.to[i]]=u; check_block(G.to[i]); }return; } int Get_pos(int u){ int L=0,R=cnt[u]; while(L<R){ int mid=L+((R-L+1)>>1); if(a[u][mid]>v)L=mid; else R=mid-1; }return L; } void Get_block(int u){ ans+=Get_pos(u); for(int i=T.h[u];i;i=T.next[i])Get_block(T.to[i]); } void Get_ask(int u){ if(w[u]>v)ans++; for(int i=G.h[u];i;i=G.next[i]){ if(G.to[i]==fa[u])continue; if(pos[G.to[i]]==pos[u])Get_ask(G.to[i]); else Get_block(pos[G.to[i]]); }return; } void Get_insert(int u,int k){ pos[u]=k;w[u]=v;a[k][++cnt[k]]=v; sort(a[k]+1,a[k]+cnt[k]+1,cmp); } void Get_modify(int u){ int k=pos[u]; for(int i=1;i<=cnt[k];++i){ if(a[k][i]==w[u]){a[k][i]=v;break;} } w[u]=v; sort(a[k]+1,a[k]+cnt[k]+1,cmp); } int main(){ read(n); for(int i=1;i<n;++i){ read(u);read(v); G.add(u,v);G.add(v,u); } for(int i=1;i<=n;++i)read(w[i]); blo=(int)(sqrt(n)); fa[1]=1;pos[1]=1;tot=1; check_block(1); for(int i=1;i<=tot;++i)sort(a[i]+1,a[i]+cnt[i]+1,cmp); //for(int i=1;i<=n;++i)cout<<pos[i]<<endl; //cout<<endl; read(m); while(m--){ read(f);read(u);read(v); u^=ans;v^=ans; if(f==0){ ans=0; Get_ask(u); printf("%d\n",ans); }else if(f==2){ n++;fa[n]=u;G.add(u,n); if(cnt[pos[u]]==blo){ pos[n]=++tot;w[n]=v;a[tot][0]=oo; a[tot][++cnt[tot]]=w[n]; T.add(pos[u],tot); }else Get_insert(n,pos[u]); }else Get_modify(u); }return 0; }