• 洛谷 P3899 [谈笑风生]


    简化题意

    m次询问,每次询问x的子树中,与x节点距离不超过y的节点的子树和。n,m≤300,000。


    思路

    按照dfs序排序,每次将一个点的答案塞到第depu的位置,这样得到一个前缀和,每次询问作减法即可。

    可持久化线段树。


    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=3E5+5;
     4 typedef long long int ll;
     5 ll n,m,x,y,sum[maxn],dep[maxn],cur,t[maxn*20],root[maxn*20],fa[maxn],size,gg;
     6 ll ls[maxn*20],rs[maxn*20],ti,dfn[maxn],last[maxn],maxx[maxn],head[maxn*2];
     7 struct edge{ll to,next;}E[maxn*2];
     8 void insert(ll l,ll r,ll pos,ll&num,ll pre,ll val)
     9 {
    10     num=++cur;
    11     t[num]=t[pre];
    12     ls[num]=ls[pre];
    13     rs[num]=rs[pre];
    14     t[num]+=val;
    15     if(l==r)return;
    16     ll mid=(l+r)>>1;
    17     if(pos<=mid)insert(l,mid,pos,ls[num],ls[pre],val);
    18     else insert(mid+1,r,pos,rs[num],rs[pre],val);
    19 }
    20 ll ask(ll L,ll R,ll l,ll r,ll num)
    21 {
    22     if(L<=l&&r<=R)return t[num];
    23     else if(r<L||R<l)return 0;
    24     ll mid=(l+r)>>1;
    25     return ask(L,R,l,mid,ls[num])+ask(L,R,mid+1,r,rs[num]);
    26 }
    27 void add(ll u,ll v)
    28 {
    29     E[++size].to=v;
    30     E[size].next=head[u];
    31     head[u]=size;
    32 }
    33 void dfs(ll u,ll F,ll d)
    34 {
    35     dep[u]=d;
    36     fa[u]=F;
    37     sum[u]=1;
    38     maxx[u]=dfn[u]=++ti;
    39     last[u]=u;
    40     for(ll i=head[u];i;i=E[i].next)
    41     {
    42         ll v=E[i].to;
    43         if(v==F)continue;
    44         dfs(v,u,d+1);
    45         sum[u]+=sum[v];
    46         if(maxx[v]>maxx[u])
    47         {
    48             maxx[u]=maxx[v];
    49             last[u]=last[v];
    50         }
    51     }
    52 }
    53 void init(ll u,ll F,ll d)
    54 {
    55     insert(1,n,d,root[u],root[gg],sum[u]-1);
    56     gg=u;
    57     for(ll i=head[u];i;i=E[i].next)
    58     {
    59         ll v=E[i].to;
    60         if(v==F)continue;
    61         init(v,u,d+1);
    62     }
    63 }
    64 int main()
    65 {
    66 //    freopen("laugh.in","r",stdin);
    67 //    freopen("laugh.out","w",stdout);
    68     ios::sync_with_stdio(false);
    69     cin>>n>>m;
    70     for(ll i=1;i<=n-1;++i)
    71     {
    72         cin>>x>>y;
    73         add(x,y);
    74         add(y,x);
    75     }
    76     dfs(1,1,1);
    77     gg=1;
    78     init(1,1,1);
    79     for(ll i=1;i<=m;++i)
    80     {
    81         cin>>x>>y;
    82         if(x==1)cout<<ask(2,1+y,1,n,root[last[1]])<<endl;
    83         else cout<<(sum[x]-1)*min(dep[x]-1,y)+
    84         ask(dep[x]+1,dep[x]+y,1,n,root[last[x]])-ask(dep[x]+1,dep[x]+y,1,n,root[x])<<endl;
    85     }
    86     return 0;
    87 }
    View Code
  • 相关阅读:
    xavier NX编译caffe错误记录(二)
    ubuntu16安装微信
    linux中安装onenote(P3X OneNote)
    ubuntu16中,google浏览器安装OneNote Web Clipper插件
    酒店门锁接口说明
    在xaf 14 中实现 Tonyyang原文中的action权限
    MRP生产计划模式在多品种小批量生产过程中遭遇挑战
    C#代码
    简陋的会计凭证金额输入控件(加强) [转]
    简陋的会计凭证金额输入控件(再加强) [转]
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/10610636.html
Copyright © 2020-2023  润新知