Codeforces Round #381 (Div. 1) B. Alyona and a tree 树+二分+前缀和+dfs / dfs序+树状数组

题目链接:

http://codeforces.com/contest/739/problem/B

题意:

一颗树1~n,以1为根节点,每个节点i都有一个对应的a[i]值,每条边有一个边权,问每个节点可以控制多少个子节点 并输出
控制的定义:dis(u,v)<=a[v]  u是v的祖先
dis(u,v)的定义:从u到v的边上的权值之和

思路:

二分,前缀和,dfs的思想: http://www.cnblogs.com/s1124yy/p/6103184.html

dfs序,树状数组的思想: http://blog.csdn.net/survivorone/article/details/53332726

都非常机智啊...

如何处理dis(u,v)<=a[v]咧,跑一遍dfs,处理出depth[i]表示i这个点到达根节点1的边权和,那么 depth[v]-depth[u]<=a[v] ----> depth[v]-a[v]<=depth[u]。 

第一种做法: 大致思想是比如dfs到当前的节点u,我们记录了dfs出的这条链的路径的边权和以及点,所以用这条链的边权和,二分出当前点的祖先不合法的最近的那个点,更新答案,使他减1,不合法就是depth[祖先]<depth[当前]-a[当前]的最低点。总之一句话: 把当前点对不合法的最近祖先的贡献删掉。

下面是复制的:

dfs扫一遍,depth[]存的是权值前缀和,前缀和存在单调性,这时就可以想到用二分了。(构造前缀和,以便用二分)

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

上面是样例的树,假如我dfs到了第4个节点,那么我就二分4 3 1这个路径的前缀和,找到能控制4的最大区间,更新这个区间,之后继续dfs第5个节点,这时修改前缀和的数组,也就是path数组,把 4 pop_back掉,把 5 push进去,这就可以二分5 3 1这条路了。

 

第二种做法:

 

1、dfs 求出每一个点距离树根的距离 depth[N],用时间戳 in[N],out[N]数组记录进出点的时间并将子节点的时间戳包含在父亲节点的时间戳之内;

2、对于每一个点,值为a[N],处理出 node(1,i,depth[i]-a[i]) 与 node(2,i,depth[i]); 两组数据,并按第3个值升序排序; [类型1是更新树状数组的,通过类型2查询比depth[i]小的有多少,就是答案啦,因为按照第3个值排序了,所以后面大的值不可能影响答案,那么如何查询一个子树对答案的贡献呢,dfs序啊,树状数组就是处理的dfs序,dfs序一颗子树一定在一段连续的标号上,所以就是 get(in[u])-get(out[u]),因为u不能算作贡献,自己不能控制自己嘛]

3、再维护一个树状数组更新、求和即可。

 

总结:

感觉第一种方法是把一颗树上的一条链上的信息维护起来,为后面二分找到不合法祖先做准备, 可能叫树链剖分?太菜,还没接触过树剖

第二种方法是用dfs序把树压成一条直线处理的。

 

代码:

代码一:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define MS(a) memset(a,0,sizeof(a))
 5 #define MP make_pair
 6 #define PB push_back
 7 const int INF = 0x3f3f3f3f;
 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
 9 inline ll read(){
10     ll x=0,f=1;char ch=getchar();
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return x*f;
14 }
15 //////////////////////////////////////////////////////////////////////////
16 const int maxn = 2e5+10;
17 
18 int n;
19 ll a[maxn];
20 vector<pair<ll,ll> > g[maxn];
21 vector<pair<ll,int> > path;
22 ll ans[maxn],depth[maxn];
23 
24 void dfs(ll u,int fa){
25     ans[u] = 1;
26     int idx = lower_bound(path.begin(),path.end(),MP(depth[u]-a[u],-1)) - path.begin();
27     idx--;
28     if(idx >= 0) ans[path[idx].second]--;
29     path.push_back(MP(depth[u],u));
30     for(int i=0; i<(int)g[u].size(); i++){
31         ll v = g[u][i].first, w = g[u][i].second;
32         if(v == fa) continue;
33         depth[v] = depth[u]+w;
34         dfs(v,u);
35         ans[u] += ans[v];
36     }
37     path.pop_back();
38 }
39 
40 int main(){
41     cin >> n;
42     for(int i=1; i<=n; i++)
43         cin >> a[i];
44     for(int i=2; i<=n; i++){
45         int to,w; cin>>to>>w;
46         g[i].push_back(MP(to,w));
47         g[to].push_back(MP(i,w));
48     }
49 
50     dfs(1,-1);
51 
52     for(int i=1; i<=n; i++)
53         cout << ans[i]-1 << " ";
54     puts("");
55 
56     return 0;
57 }

代码二:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define MS(a) memset(a,0,sizeof(a))
 5 #define MP make_pair
 6 #define PB push_back
 7 const int INF = 0x3f3f3f3f;
 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
 9 inline ll read(){
10     ll x=0,f=1;char ch=getchar();
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
13     return x*f;
14 }
15 //////////////////////////////////////////////////////////////////////////
16 const int maxn = 2e5+10;
17 
18 int n;
19 vector<pair<ll,ll> > g[maxn];
20 ll a[maxn],tot,depth[maxn],ans[maxn],bit[maxn*4],in[maxn],out[maxn];
21 
22 void dfs(int u,int fa){
23     in[u] = ++tot;
24     for(int i=0; i<(int)g[u].size(); i++){
25         ll v = g[u][i].first,w = g[u][i].second;
26         if(v == fa) continue;
27         depth[v] = depth[u]+w;
28         dfs(v,u);
29     }
30     out[u] = tot;
31 }
32 
33 struct node{
34     ll type,u,sum;
35     node(){}
36     node(ll x,ll y,ll z){
37         type = x; u = y; sum = z;
38     }
39 }k[maxn*2];
40 
41 bool cmp(node A,node B){
42     if(A.sum == B.sum) return A.type<B.type;
43     return A.sum<B.sum;
44 }
45 
46 void add(int x){
47     while(x < maxn*4){
48         bit[x]++;
49         x += x&-x;
50     }
51 }
52 
53 ll get(int x){
54     ll res = 0;
55     while(x > 0){
56         res += bit[x];
57         x -= x&-x;
58     }
59     return res;
60 }
61 
62 int main(){
63     cin >> n;
64     for(int i=1; i<=n; i++)
65         a[i]=read();
66     for(int i=2; i<=n; i++){
67         ll to,w; scanf("%I64d%I64d",&to,&w);
68         g[i].push_back(MP(to,w));
69         g[to].push_back(MP(i,w));
70     }
71     dfs(1,-1);
72     int cnt = 1;
73     for(int i=1; i<=n; i++){
74         k[cnt++] = node{1,i,depth[i]-a[i]};
75         k[cnt++] = node{2,i,depth[i]};
76     }
77     sort(k+1,k+cnt,cmp);
78     for(int i=1; i<cnt; i++){
79         if(k[i].type == 1){
80             add(in[k[i].u]);
81         }else{
82             ans[k[i].u] = get(out[k[i].u]) - get(in[k[i].u]);
83         }
84     }
85     for(int i=1; i<=n; i++){
86         cout << ans[i] << " ";
87     }
88     puts("");
89 
90     return 0;
91 }

 

posted @ 2017-06-05 18:44  _yxg123  阅读(186)  评论(0编辑  收藏  举报