zoukankan      html  css  js  c++  java
  • 主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生

    题面: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
    ",ans);
    95     }
    96     return 0;
    97 }

    By:AlenaNuna

  • 相关阅读:
    [hdu5312]数的拆分,数学推导
    [POJ1038]状压DP
    [hdu2112]最短路
    [hdu1532]最大流
    [hdu5256]LIS模型
    [hdu5255]枚举
    [hdu5254]BFS
    [hdu5270]按位统计,容斥,归并
    Elasticsearch在Centos 7上的安装与配置
    手动安装java1.8
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/10492434.html
Copyright © 2011-2022 走看看