动态树

题目链接

Solution:

        首先考虑对每个询问做一些合法的修改,对于一个询问(u,l,r),设now为当前询问时的总节点个数,若l>now,则询问答案为0;若r>now,则我们将r改成now也没有关系。接下来把每一个改好的询问拆成(u,1,r)和(u,1,l-1)两个,真实答案可由两个询问的答案相减得到。

        接下来我们对每个询问(u,1,x)按x排好序,从1号开始一个一个加点,当now=x时,就可以回答(u,1,x)的询问。

        具体方法:计算以u为根的子树当中已加点的个数n1和点的总深度n2,则Ans=n2-n1*dep[u].

        用线段树或是树桩数组,单点修改,DFS序上区间查询。

Code:

#include
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template void read(T &num){
	char c=getchar();T f=1;num=0;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
	num*=f;
}
template void qwq(T x){
	if(x>9)qwq(x/10);
	putchar(x%10+'0');
}
template void write(T x){
	if(x<0){x=-x;putchar('-');}
	qwq(x);putchar('\n');
}
struct wzy{
	int nxt,vertice;
}edge[2100010];
int head[1400010];int len=0;int now;
inline void add_edge(int x,int y){
	edge[++len].nxt=head[x];edge[len].vertice=y;head[x]=len;return;
}
struct hry{
	int q,x,pos;
}que[1400010];
inline bool cmp(hry a,hry b){
	return a.xnow){tot++;ans[tot/2+1]=0;tot++;continue;}
			if(r>now)r=now;
			que[++tot].q=u;que[tot].x=l-1;que[tot].pos=tot/2+1;
			que[++tot].q=u;que[tot].x=r;que[tot].pos=tot/2;
		}
	}
	Pretreatment(1,0);
	sort(que+1,que+tot+1,cmp); 
	
	int c=0;
	rep(i,1,tot){
		if(!que[i].q)continue;
		int nop=que[i].x;int nop2=que[i].q;
		rep(j,c+1,nop){change(id[j],dep[j],0);change(id[j],1,1);}
		c=nop;
		long long n1=query(id[nop2]+siz[nop2]-1,0)-query(id[nop2]-1,0);
		long long n2=query(id[nop2]+siz[nop2]-1,1)-query(id[nop2]-1,1);
		long long f=n1-n2*dep[nop2];
		if(in[que[i].pos]){ans[que[i].pos]+=f;}
		else{ans[que[i].pos]-=f;in[que[i].pos]=1;}
	}
	rep(i,1,tot/2)write(ans[i]);
	return 0;
}

 

你可能感兴趣的:(树状数组)