主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生
题解:
我很喜欢这道题。
因为A是给定的,所以实质是求二元组的个数。我们以A(即给定的P)作为基点寻找答案,那么情况分两类。一种是B为A的父亲,另一种是A为B的父亲。
第一种情况很好处理,写法见代码,懒得讲,反正很简单的。
第二种情况的话,按Dfs序建主席树,用主席树维护下标为Dep的序列,每次用Size-1(因为不能取本身;Size[i]即为以i为根的子树节点数)去更新,
询问的时候在以A为根的子树中查找Dep[A]+1~Dep[A]+K的和即可。
不思考自然是看不懂的。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 #define max(a,b) ((a)>(b)?(a):(b)) 6 using namespace std; 7 inline ll rd(){ 8 ll x=0,f=1;char c=getchar(); 9 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 10 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 11 return f*x; 12 } 13 const int maxn=(3e5)+50,maxq=(3e5)+50; 14 int N,Q,num_edge=0,edge_head[maxn],U,V,Le[maxn],Ri[maxn],P,root[maxn],num_treenode=0,maxdep; 15 int Dfn[maxn],num_dfn=0; 16 struct Edge{int to,nx;}edge[maxn<<1]; 17 ll Dep[maxn],Size[maxn],K,w,ans; 18 inline void Add_edge(int from,int to){ 19 edge[++num_edge].nx=edge_head[from]; 20 edge[num_edge].to=to; 21 edge_head[from]=num_edge; 22 return; 23 } 24 struct Tree{int l,r,ls,rs;ll sum;}t[(maxn<<3)+(maxn*20)]; 25 inline void Build(int x,int l,int r){//建以深度为下标的主席树 26 t[x].l=l;t[x].r=r;int mid=(l+r)>>1; 27 if(l==r)return; 28 Build(t[x].ls=++num_treenode,l,mid); 29 Build(t[x].rs=++num_treenode,mid+1,r); 30 return; 31 } 32 inline void Dfs(int x,int fa){ 33 Dfn[++num_dfn]=x; 34 Le[x]=num_dfn; 35 Dep[x]=Dep[fa]+1; 36 maxdep=max(maxdep,Dep[x]); 37 Size[x]=1; 38 for(int i=edge_head[x];i;i=edge[i].nx){ 39 int y=edge[i].to; 40 if(y!=fa){ 41 Dfs(y,x); 42 Size[x]+=Size[y]; 43 } 44 } 45 Ri[x]=num_dfn; 46 return; 47 } 48 inline void Update(int u,int x,int q,int s){ 49 int l=t[u].l,r=t[u].r,mid=(l+r)>>1; 50 t[x].l=l;t[x].r=r; 51 if(l==r&&l==q){t[x].sum=t[u].sum+s; return;} 52 if(q<=mid){ 53 t[x].rs=t[u].rs; 54 Update(t[u].ls,t[x].ls=++num_treenode,q,s); 55 } 56 else{ 57 t[x].ls=t[u].ls; 58 Update(t[u].rs,t[x].rs=++num_treenode,q,s); 59 } 60 t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum; 61 return; 62 } 63 inline void Query(int u,int x,int ql,int qr){ 64 int l=t[u].l,r=t[u].r,mid=(l+r)>>1; 65 if(ql<=l&&r<=qr){ 66 ans=ans+t[x].sum-t[u].sum; 67 return; 68 } 69 if(ql<=mid)Query(t[u].ls,t[x].ls,ql,qr); 70 if(qr>mid) Query(t[u].rs,t[x].rs,ql,qr); 71 return; 72 } 73 int main(){ 74 N=rd();Q=rd(); 75 for(int i=1;i<N;i++){ 76 U=rd();V=rd(); 77 Add_edge(U,V); 78 Add_edge(V,U); 79 } 80 Dep[0]=-1;//由于我的写法的原因,把根节点的深度设为0 81 Dfs(1,0); 82 Build(root[0]=++num_treenode,1,maxdep+5); 83 Dfn[0]=0; 84 for(int i=1;i<=num_dfn;i++) 85 Update(root[Dfn[i-1]],root[Dfn[i]]=++num_treenode,Dep[Dfn[i]],Size[Dfn[i]]-1); 86 while(Q--){ 87 P=rd();K=rd(); 88 ans=0; 89 //先往父亲找 90 if(Dep[P]>=K)w=K;else w=Dep[P]; 91 ans+=w*(Size[P]-1); 92 //往儿子找 93 Query(root[P],root[Dfn[Ri[P]]],Dep[P]+1,Dep[P]+K); 94 printf("%lld\n",ans); 95 } 96 return 0; 97 }
By:AlenaNuna