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 */