【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\n",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]
posted @ 2015-04-18 23:38  Tunix  阅读(681)  评论(0编辑  收藏  举报