bzoj 1103

题目大意:有一棵树根为1,刚开始每条边的权值为1,  现在有m + n - 1 个操作, A :x  y  , 将x和y相连的边权值变为1, W:x, 询问x到1路径上的权值和。

 

思路 : 方法一: 用dfs序建立树状数组, 每个点入栈位置的值为1, 出栈为-1, 询问的值就是sum( l [ x ] ), 修改就将出栈,入栈的点全部变成1, 巧妙的地方在于

利用dfs序求前缀和会把不是在这条链上的边全部抵消掉。

 

方法二:用dfs序建立线段数, 线段数里每个点表示该点到1的权值和, 修改一条边相当于把该边下边的子树的值全部减1, 相当于区间修改。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define fi first
 4 #define se second
 5 #define mk make_pair
 6 #define pii pair<int,int>
 7 
 8 using namespace std;
 9 
10 const int N=5e5+7;
11 const int M=1e4+7;
12 const int inf=0x3f3f3f3f;
13 const LL INF=0x3f3f3f3f3f3f3f3f;
14 const int mod=1e9 + 7;
15 
16 int n, m, tot, st[N], l[N], r[N];
17 
18 struct BIT {
19     int a[N];
20     void modify(int pos, int v) {
21         for(int i = pos; i <= tot; i += i & -i)
22             a[i] += v;
23     }
24 
25     int sum(int pos) {
26         int ans = 0;
27         for(int i = pos; i; i -= i & -i)
28             ans += a[i];
29         return ans;
30     }
31 }bit;
32 
33 vector<int> edge[N];
34 void dfs(int u) {
35     l[u] = ++tot;
36     for(int i = 0; i < edge[u].size(); i++) {
37         int v = edge[u][i];
38         dfs(v);
39     }
40     r[u] = ++tot;
41 }
42 int main() {
43     scanf("%d", &n);
44     for(int i = 1; i < n; i++) {
45         int u, v; scanf("%d%d", &u, &v);
46         if(u > v) swap(u, v);
47         edge[u].push_back(v);
48     }
49     dfs(1);
50     for(int i = 1; i <= n; i++) {
51         bit.modify(l[i], 1);
52         bit.modify(r[i], -1);
53     }
54     scanf("%d", &m);
55     m += n - 1;
56     while(m--) {
57         char s[5]; scanf("%s", s);
58         if(s[0] == 'A') {
59             int u, v; scanf("%d%d", &u, &v);
60             if(u > v) swap(u, v);
61             bit.modify(l[v], -1);
62             bit.modify(r[v], 1);
63         } else {
64             int x; scanf("%d", &x);
65             printf("%d\n", bit.sum(l[x]) - 1);
66         }
67     }
68     return 0;
69 }
70 /*
71 */

 

posted @ 2018-05-07 21:23  NotNight  阅读(144)  评论(0编辑  收藏  举报