• 【BZOJ】【3653】谈笑风生


    dfs序+可持久化线段树


      好吧……是我too naive

      这题……$$ans=min(dep[x],k)×(size[x]-1)+sum_{y在x的子树中,且dis(x,y)<=k}(size[y]-1)$$

      那么重点是后面sigma的部分,这里看到子树中信息的统计可以用dfs序……但是对子树中dep在某个范围内的点的size求和?

      我们可以用权值线段树呀~dep做关键字,size的和是线段树上统计的额外信息,那么对整个dfs序做可持久化线段树就可以了……查询的时候就像普通线段树一样。

    调了很久的一个地方……

     1 F(i,1,n) update(root[i]=root[i-1],0,n,dep[a[i]],sz[a[i]]-1); 

    这一句中我一开始写成.......dep[a[x]],sz[a[x]]-1了!!

    因为在dfs的过程中我是用x这个变量来表示某个节点的……然后这里顺着思路就写下来了……

    你可能会说,为什么没有CE呢?那是因为我在读入边的时候声明了两个变量x,y……看代码上下文就知道了TAT

     1 /**************************************************************
     2     Problem: 3653
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:8964 ms
     7     Memory:158752 kb
     8 ****************************************************************/
     9  
    10 //Huce #1 D
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=3e5+10,INF=~0u>>2;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 int head[N],to[N<<1],next[N<<1],cnt;
    32 void add(int x,int y){
    33     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
    34     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt;
    35 }
    36 int n,m,a[N],dep[N],sz[N],st[N],ed[N],root[N],tot,ct;
    37 struct Tree{
    38     int l,r; LL sum;
    39 }t[N*30];
    40 #define mid (l+r>>1)
    41 void update(int &o,int l,int r,int pos,int w){
    42     t[++ct]=t[o], o=ct, t[o].sum+=w;
    43     if (l==r) return;
    44     if (pos<=mid) update(t[o].l,l,mid,pos,w);
    45     else update(t[o].r,mid+1,r,pos,w);
    46 }
    47 LL query(int i,int j,int l,int r,int ql,int qr){
    48     if (ql<=l && qr>=r){
    49         return t[j].sum-t[i].sum;
    50     }else{
    51         LL ans=0;
    52         if (ql<=mid) ans+=query(t[i].l,t[j].l,l,mid,ql,qr);
    53         if (qr> mid) ans+=query(t[i].r,t[j].r,mid+1,r,ql,qr);
    54         return ans;
    55     }
    56 }
    57 #undef mid
    58 void dfs(int x){
    59     a[st[x]=++tot]=x;
    60     sz[x]=1;
    61     for(int i=head[x];i;i=next[i])
    62         if (st[to[i]]==0){
    63             dep[to[i]]=dep[x]+1;
    64             dfs(to[i]);
    65             sz[x]+=sz[to[i]];
    66         }
    67     ed[x]=tot;
    68 }
    69  
    70 int main(){
    71 #ifndef ONLINE_JUDGE
    72     freopen("D.in","r",stdin);
    73     freopen("D.out","w",stdout);
    74 #endif
    75     n=getint(); m=getint();
    76     int x,y;
    77     F(i,2,n){
    78         x=getint(); y=getint();
    79         add(x,y);
    80     }
    81     dfs(1);
    82     F(i,1,n) update(root[i]=root[i-1],0,n,dep[a[i]],sz[a[i]]-1);
    83     F(i,1,m){
    84         x=getint(); y=getint();
    85         LL ans=(LL)(sz[x]-1)*min(dep[x],y);
    86         ans+=query(root[st[x]-1],root[ed[x]],0,n,
    87                    dep[x]+1,min(dep[x]+y,n));
    88         printf("%lld
    ",ans);
    89     }
    90     return 0;
    91 }
    92 
    View Code

    3653: 谈笑风生

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 225  Solved: 79
    [Submit][Status][Discuss]

    Description

    设T 为一棵有根树,我们做如下的定义:
    • 设a和b为T 中的两个不同节点。如果a是b的祖先,那么称“a比b不知道
    高明到哪里去了”。
    • 设a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定
    常数x,那么称“a 与b 谈笑风生”。
    给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点。你需
    要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足:
    1. a、b和 c为 T 中三个不同的点,且 a为p 号节点;
    2. a和b 都比 c不知道高明到哪里去了;
    3. a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。

    Input

    输入文件的第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。
    接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。


    Output

    输出 q 行,每行对应一个询问,代表询问的答案。

    Sample Input

    5 3
    1 2
    1 3
    2 4
    4 5
    2 2
    4 1
    2 3

    Sample Output


    3
    1
    3

    HINT


    1<=P<=N

    1<=K<=N

    N<=300000

    Q<=300000

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    字符串的输入输出 附带一道练习题
    NOIP2009 1.多项式输出
    算法--欧几里得
    小程序:2048
    虚函数和多态
    c++学习记录(十五)
    面向对象程序设计寒假作业3
    c++学习记录(十四)
    c++学习记录(十三)
    c++学习记录(十二)
  • 原文地址:https://www.cnblogs.com/Tunix/p/4438400.html
Copyright © 2020-2023  润新知