[HAOI2015]树上操作
树剖自然可解,就是一道板子题,而且这道题还只问到根节点的距离是多少,而不是树上任意两点距离,就更方便了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter printf("\n") 13 #define space printf(" ") 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 #define int long long 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const int eps = 1e-8; 20 const int maxn = 1e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) 27 { 28 ans = ans * 10 + ch - '0'; ch = getchar(); 29 } 30 if(last == '-') ans = -ans; 31 return ans; 32 } 33 inline void write(ll x) 34 { 35 if(x < 0) x = -x, putchar('-'); 36 if(x >= 10) write(x / 10); 37 putchar(x % 10 + '0'); 38 } 39 40 int n, m; 41 ll a[maxn]; 42 vector<int> v[maxn]; 43 44 bool vis[maxn]; 45 int dep[maxn], fa[maxn], son[maxn], size[maxn]; 46 void dfs1(int now) 47 { 48 size[now] = 1; vis[now] = 1; 49 for(int i = 0; i < (int)v[now].size(); ++i) 50 { 51 if(!vis[v[now][i]]) 52 { 53 dep[v[now][i]] = dep[now] + 1; 54 fa[v[now][i]] = now; 55 dfs1(v[now][i]); 56 size[now] += size[v[now][i]]; 57 if(!son[now] || size[v[now][i]] > size[son[now]]) son[now] = v[now][i]; 58 } 59 } 60 } 61 62 int dfsx[maxn], pos[maxn], top[maxn], cnt = 0; 63 void dfs2(int now) 64 { 65 vis[now] = 1; dfsx[now] = ++cnt; pos[cnt] = now; 66 if(son[now]) 67 { 68 top[son[now]] = top[now]; 69 dfs2(son[now]); 70 } 71 for(int i = 0; i < (int)v[now].size(); ++i) 72 { 73 if(!vis[v[now][i]] && v[now][i] != son[now]) 74 { 75 top[v[now][i]] = v[now][i]; 76 dfs2(v[now][i]); 77 } 78 } 79 } 80 81 int l[maxn << 2], r[maxn << 2]; 82 ll sum[maxn << 2], lazy[maxn << 2]; 83 void build(int L, int R, int now) 84 { 85 l[now] = L; r[now] = R; 86 if(L == R) {sum[now] = a[pos[L]]; return;} 87 int mid = (L + R) >> 1; 88 build(L, mid, now << 1); 89 build(mid + 1, R, now << 1 | 1); 90 sum[now] = sum[now << 1] + sum[now << 1 | 1]; 91 } 92 void pushdown(int now) 93 { 94 if(lazy[now]) 95 { 96 lazy[now << 1] += lazy[now]; 97 lazy[now << 1 | 1] += lazy[now]; 98 sum[now << 1] += lazy[now] * (r[now << 1] - l[now << 1] + 1); 99 sum[now << 1 | 1] += lazy[now] * (r[now << 1 | 1] - l[now << 1 | 1] + 1); 100 lazy[now] = 0; 101 } 102 } 103 void update(int L, int R, int now, int d) 104 { 105 if(l[now] == L && r[now] == R) 106 { 107 sum[now] += d * (R - L + 1); 108 lazy[now] += d; return; 109 } 110 pushdown(now); 111 int mid = (l[now] + r[now]) >> 1; 112 if(R <= mid) update(L, R, now << 1, d); 113 else if(L > mid) update(L, R, now << 1 | 1, d); 114 else update(L, mid, now << 1, d), update(mid + 1, R, now << 1 | 1, d); 115 sum[now] = sum[now << 1] + sum[now << 1 | 1]; 116 } 117 ll query(int L, int R, int now) 118 { 119 if(l[now] == L && r[now] == R) return sum[now]; 120 pushdown(now); 121 int mid = (l[now] + r[now]) >> 1; 122 if(R <= mid) return query(L, R, now << 1); 123 else if(L > mid) return query(L, R, now << 1 | 1); 124 else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1); 125 } 126 127 ll query_path(int x) 128 { 129 ll ret = 0; 130 while(top[x] != top[1]) 131 { 132 ret += query(dfsx[top[x]], dfsx[x], 1); 133 x = fa[top[x]]; 134 } 135 ret += query(dfsx[top[1]], dfsx[x], 1); 136 return ret; 137 } 138 139 main() 140 { 141 n = read(); m = read(); 142 for(int i = 1; i <= n; ++i) a[i] = read(); 143 for(int i = 1; i < n; ++i) 144 { 145 int x = read(), y = read(); 146 v[x].push_back(y); v[y].push_back(x); 147 } 148 dfs1(1); Mem(vis); 149 top[1] = 1; dfs2(1); //别忘top[1] = 1 150 build(1, cnt, 1); 151 for(int i = 1; i <= m; ++i) 152 { 153 int d = read(), x = read(); 154 if(d == 1) 155 { 156 int c = read(); 157 update(dfsx[x], dfsx[x], 1, c); 158 } 159 else if(d == 2) 160 { 161 int c = read(); 162 update(dfsx[x], dfsx[x] + size[x] - 1, 1, c); 163 } 164 else write(query_path(x)), enter; 165 } 166 // return 0; 167 }
写完树剖后发现线段树也可以,只要先跑一边dfs序,同时维护每一个点到根节点的路径的权值和,然后修改就是正常的区间修改,因为dfs序满足同一棵子树序号连续。然后单点查询。有兴趣的可以自己写一下~~