zoukankan      html  css  js  c++  java
  • 【主席树】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
    ",(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;
    }
  • 相关阅读:
    截屏 多难未遂
    捕捉异常
    Android中缓存记忆
    Android中的线程池
    悄悄为Android中解决部分适配问题哦!
    java中的服务端跳转与客户端跳转区别与联系
    doget(),doput()方法的使用
    基本概念--同步,异步
    java--SimpleDataFormat类
    java--9
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4424986.html
Copyright © 2011-2022 走看看