【主席树】bzoj3653 谈笑风生

设siz[i]表示i的子树大小-1。

询问中b在a上方的便于统计。

对于b在a下方的情况,贡献为距a距离在K以内的节点的siz之和。

按dfs序建立可持久化线段树,线段树的下标是深度。

相当于把每个点(带权)映射到了平面上,然后求一个矩形内的点权之和。

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 300001
typedef long long ll;
struct Node{int lc,rc;ll v;}T[N*24];
int root[N];
int en,v[N<<1],first[N],next[N<<1],siz[N],dep[N],Ls[N],e,Rs[N];
int ma_siz[N],ma_dep[N];
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
void dfs(int U,int Fa)
{
	siz[U]=1; Ls[U]=++e;
	dep[U]=dep[Fa]+1;
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=Fa)
	    {
	      dfs(v[i],U);
	      siz[U]+=siz[v[i]];
	    }
	Rs[U]=e;
}
int n,m;
void Update(int pre,int cur,int p,int v,int l,int r)
{
	if(l==r)
	  {
	  	T[cur].v=T[pre].v+(ll)v;
	  	return;
	  }
	int m=(l+r>>1);
	if(p<=m)
	  {
	  	T[cur].lc=++e;
	  	T[cur].rc=T[pre].rc;
	  	Update(T[pre].lc,T[cur].lc,p,v,l,m);
	  }
	else
	  {
	  	T[cur].rc=++e;
	  	T[cur].lc=T[pre].lc;
	  	Update(T[pre].rc,T[cur].rc,p,v,m+1,r);
	  }
	T[cur].v=T[T[cur].lc].v+T[T[cur].rc].v;
}
ll Query(int pre,int cur,int ql,int qr,int l,int r)
{
	if(ql<=l&&r<=qr) return T[cur].v-T[pre].v;
	int m=(l+r>>1); ll res=0;
	if(ql<=m) res+=Query(T[pre].lc,T[cur].lc,ql,qr,l,m);
	if(m<qr) res+=Query(T[pre].rc,T[cur].rc,ql,qr,m+1,r);
	return res;
}
int main()
{
	int x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;++i)
	  {
	  	scanf("%d%d",&x,&y);
	  	AddEdge(x,y);
	  	AddEdge(y,x);
	  }
	dfs(1,0); e=0;
	for(int i=1;i<=n;++i)
	  {
	  	--siz[i];
	  	ma_siz[Ls[i]]=siz[i];
	  	ma_dep[Ls[i]]=dep[i];
	  }
	for(int i=1;i<=n;++i)
	  {
	  	root[i]=++e;
	  	Update(root[i-1],root[i],ma_dep[i],ma_siz[i],1,n);
	  }
	for(;m;--m)
	  {
	  	scanf("%d%d",&x,&y);
	  	printf("%lld\n",(ll)min(dep[x]-1,y)*(ll)siz[x]+
		Query(root[Ls[x]],root[Rs[x]],dep[x]+1,min(dep[x]+y,n),1,n));
	  }
	return 0;
}
posted @ 2015-04-14 15:14  AutSky_JadeK  阅读(176)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト