块状树裸题
首先将树分块:
如果父亲的块不是满的,就将自己添加进块里
否则自己单独形成一个块
可以证明:每个块都是一个联通块
之后考虑操作:
对于操作0,我们暴力询问就可以了
块不完全在询问范围->单点询问
块完全在询问范围->块询问
对于操作1 随便改一改就好了
对于操作2 考虑父亲的块是不是满的,随便改一改就好了
分块真是骗分的利器
然而块状树的缺点是如果有菊花树分出的块就很带感了
修改其实有不带log的做法,然而并不想写
#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;
}