BZOJ3720: Gty的妹子树

用“重量平衡树”实现的ETT套平衡树就可以做到$O(nlog^2n)$了。然而我很无聊地写了个$O(nsqrt{nlog n})$的根号重构,就是每$O(sqrt{nlog n})$次修改就用$O(nlog n)$的代价重构函数式trie。

#include<cstdio>
#include<vector>
#define pb push_back
const int N=60005;
struct node{
	node*i,*j;
	int s;
}e[N*30];
node*now,*r[N];
void ins(int k,node**o){
	for(int i=29;~i;--i){
		*++now=**o,*o=now;
		if(~k>>i&1)o=&(*o)->i;
		else
			++(*o)->s,o=&(*o)->j;
	}
}
int ask(int k,node*o){
	int s=0;
	for(int i=29;~i;--i)
		if(k>>i&1)o=o->j;
		else
			s+=o->s,o=o->i;
	return s;
}
int ask(int k,int u,int v){
	return ask(k,r[v])-ask(k,r[u-1]);
}
int dfn,p[N],f1[N],f2[N],w[N],f3[N],vis[N];
std::vector<int>c,t,g[N];
void dfs(int u){
	f1[u]=++dfn,r[dfn]=r[dfn-1],ins(w[u],r+dfn);
	for(int i=0;i<g[u].size();++i){
		int v=g[u][i];
		if(v!=p[u])p[v]=u,dfs(v);
	}
	f2[u]=dfn;
}
int dfs2(int u,int k){
	int s=w[u]>k;
	for(int i=0;i<g[u].size();++i){
		int v=g[u][i];
		if(v!=p[u])s+=dfs2(v,k);
	}
	return s;
}
bool jud(int v,int u){
	return f1[u]<=f1[v]&&f1[v]<=f2[u];
}
void reb(){
	for(int i=0;i<c.size();++i)
		w[c[i]]=t[i];
	c.clear();
	t.clear();
	dfn=0,now=e,dfs(1);
}
int main(){
	*(*r=e)={e,e};
	int n,m,o,u,v,s=0;
	scanf("%d",&n);
	for(int i=2;i<=n;++i)
		scanf("%d%d",&u,&v),g[u].pb(v),g[v].pb(u);
	for(int i=1;i<=n;++i)
		scanf("%d",w+i);
	reb();
	scanf("%d",&m);
	for(int k=1;k<=m;++k){
		scanf("%d%d%d",&o,&u,&v),u^=s,v^=s;
		if(!o){
			if(c.size()+n-dfn>3000)
				reb();
			if(u>dfn)s=dfs2(u,v);
			else{
				s=ask(v,f1[u],f2[u]);
				for(int i=c.size()-1;~i;--i)
					if(jud(c[i],u)&&k!=vis[c[i]]){
						vis[c[i]]=k;
						if(w[c[i]]>v)--s;
						if(t[i]>v)++s;
					}
				for(int i=n;i>dfn;--i)
					if(jud(f3[i],u))s+=w[i]>v;
			}
			printf("%d
",s);
		}
		if(o==1)
			if(u>dfn)w[u]=v;
			else
				c.pb(u),t.pb(v);
		if(o==2){
			++n,p[n]=u,w[n]=v;
			f3[n]=u>dfn?f3[u]:u;
			g[u].pb(n);
			g[n].pb(u);
		}
	}
}
原文地址:https://www.cnblogs.com/f321dd/p/8232660.html