题意:一个图有n个点,n条边,定义D(u,v)为u到v的距离,S(u,k)为所有D(u,v)<=k的节点v的集合 有m次询问(0<=k<=2):
1 u k d:将集合S(u,k)的所有节点的权值加d
2 u k:询问集合S(u,k)的所有节点的权值之和
析:把这个图树成两部分,一个是一个环,然后剩下的森林。
这个环可以用拓扑来求,看这个博客吧,讲的非常细了。
http://blog.csdn.net/qq_31759205/article/details/75049074
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> #include <cmath> #include <stack> #include <sstream> #include <list> #include <assert.h> #include <bitset> #include <numeric> #define debug() puts("++++"); #define gcd(a, b) __gcd(a, b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a, b, sizeof a) //#define sz size() #define pu push_up #define pd push_down #define cl clear() #define all 1,n,1 #define FOR(i,x,n) for(int i = (x); i < (n); ++i) #define freopenr freopen("in.txt", "r", stdin) #define freopenw freopen("out.txt", "w", stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<LL, int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e17; const double inf = 1e20; const double PI = acos(-1.0); const double eps = 1e-8; const int maxn = 1e5 + 10; const int maxm = 1e6 + 5; const int mod = 10007; const int dr[] = {-1, 0, 1, 0}; const int dc[] = {0, -1, 0, 1}; const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; int n, m; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline bool is_in(int r, int c) { return r >= 0 && r < n && c >= 0 && c < m; } struct Edge{ int to, next; }; Edge edge[maxn<<1]; int head[maxn], cnt; int in[maxn]; void addEdge(int u, int v){ edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; ++in[v]; } void topsort(){ queue<int> q; for(int i = 1; i <= n; ++i) if(in[i] == 1) q.push(i); while(!q.empty()){ int u = q.front(); q.pop(); for(int i = head[u]; ~i; i = edge[i].next){ int v = edge[i].to; if(in[v] > 1){ --in[v]; if(in[v] == 1) q.push(v); } } } } int ch[maxn][2], p[maxn], fp[maxn], pos; int fa[maxn]; int sonL[maxn], sonR[maxn], ssonL[maxn], ssonR[maxn]; void bfs(int s){ queue<int> q; q.push(s); while(!q.empty()){ int u = q.front(); q.pop(); sonL[u] = ssonL[u] = INF; sonR[u] = ssonR[u] = 0; for(int i = head[u]; ~i; i = edge[i].next){ int v = edge[i].to; if(in[v] > 1 || fa[u] == v) continue; p[v] = ++pos; fp[pos] = v; fa[v] = u; sonL[u] = min(sonL[u], p[v]); sonR[u] = max(sonR[u], p[v]); q.push(v); } ssonL[fa[u]] = min(ssonL[fa[u]], sonL[u]); ssonR[fa[u]] = max(ssonR[fa[u]], sonR[u]); } } LL sum[maxn<<2], addv[maxn<<2]; inline void push_up(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } inline void push_down(int rt, int len){ int l = rt<<1, r = rt<<1|1; sum[l] += (len - (len>>1)) * addv[rt]; sum[r] += (len>>1) * addv[rt]; addv[l] += addv[rt]; addv[r] += addv[rt]; addv[rt] = 0; } void update(int L, int R, int val, int l, int r, int rt){ if(L > R) return ; if(L <= l && r <= R){ sum[rt] += (LL)(r - l + 1) * val; addv[rt] += val; return ; } if(addv[rt]) pd(rt, r - l + 1); int m = l + r >> 1; if(L <= m) update(L, R, val, lson); if(R > m) update(L, R, val, rson); pu(rt); } LL query(int L, int R, int l, int r, int rt){ if(L > R) return 0LL; if(L <= l && r <= R) return sum[rt]; if(addv[rt]) pd(rt, r - l + 1); int m = l + r >> 1; LL ans = 0; if(L <= m) ans = query(L, R, lson); if(R > m) ans += query(L, R, rson); return ans; } void praper(){ topsort(); for(int u = 1; u <= n; ++u) if(in[u] > 1){ int j = 0; for(int i = head[u]; ~i; i = edge[i].next){ int v = edge[i].to; if(in[v] > 1) ch[u][j++] = v; } p[u] = ++pos; fp[pos] = u; fa[u] = 0; bfs(u); } } void init(){ ms(head, -1); cnt = 0; ms(in, 0); pos = 0; ms(sum, 0); ms(addv, 0); } void update(int u, int k, int val){ int f = fa[u]; if(k == 0) update(p[u], p[u], val, all); // self else if(k == 1){ if(in[u] > 1){ // on the circle update(p[ch[u][0]], p[ch[u][0]], val, all); // left neighbor update(p[ch[u][1]], p[ch[u][1]], val, all); // right neighbor } else // not on the circle update(p[f], p[f], val, all); // its father update(sonL[u], sonR[u], val, all); // left son - right son update(p[u], p[u], val, all); //self } else { if(in[u] > 1){ // on the circle int vv[2], cnt = 0; for(int i = 0; i < 2; ++i){ int v = ch[u][i]; update(p[v], p[v], val, all); // its neighbor update(sonL[v], sonR[v], val, all); // its neighbor's sons for(int j = 0; j < 2; ++j){ int t = ch[v][j]; if(t == u || t == ch[u][i^1]) continue; // insure not calculate twice times if(cnt == 1 && vv[0] == t) continue; vv[cnt++] = t; } } for(int i = 0; i < cnt; ++i) update(p[vv[i]], p[vv[i]], val, all); // its neighbor's neighbor update(p[u], p[u], val, all); // self take care the below have no } else{ // not on the circle update(p[f], p[f], val, all); // its father update(sonL[f], sonR[f], val, all); // its father's son if(in[f] > 1){ // its father is on the circle update(p[ch[f][0]], p[ch[f][0]], val, all); // its father's left neighbor update(p[ch[f][1]], p[ch[f][1]], val, all); // its father's fight neighbor } else // its father is not on the circle update(p[fa[f]], p[fa[f]], val, all); // its father's father } update(sonL[u], sonR[u], val, all); // sons update(ssonL[u], ssonR[u], val, all); // ssons } } LL query(int u, int k){ // the same as update int f = fa[u]; LL ans = 0; if(k == 0) return query(p[u], p[u], all); else if(k == 1){ ans = query(sonL[u], sonR[u], all) + query(p[u], p[u], all); if(in[u] == 1) ans += query(p[f], p[f], all); else ans += query(p[ch[u][0]], p[ch[u][0]], all) + query(p[ch[u][1]], p[ch[u][1]], all); } else{ ans = query(sonL[u], sonR[u], all) + query(ssonL[u], ssonR[u], all); if(in[u] > 1){ ans += query(p[u], p[u], all); int vv[2], cnt = 0; for(int i = 0; i < 2; ++i){ int v = ch[u][i]; ans += query(p[v], p[v], all); ans += query(sonL[v], sonR[v], all); for(int j = 0; j < 2; ++j){ int t = ch[v][j]; if(t == u || t == ch[u][i^1]) continue; if(cnt == 1 && t == vv[0]) continue; vv[cnt++] = t; } } for(int i = 0; i < cnt; ++i) ans += query(p[vv[i]], p[vv[i]], all); } else { ans += query(p[f], p[f], all) + query(sonL[f], sonR[f], all); if(in[f] > 1) ans += query(p[ch[f][0]], p[ch[f][0]], all) + query(p[ch[f][1]], p[ch[f][1]], all); else ans += query(p[fa[f]], p[fa[f]], all); } } return ans; } int main(){ int T; cin >> T; while(T--){ scanf("%d", &n); init(); for(int i = 0; i < n; ++i){ int u, v; scanf("%d %d", &u, &v); addEdge(u, v); addEdge(v, u); } praper(); scanf("%d", &m); char op[10]; int u, k, d; while(m--){ scanf("%s %d %d", op, &u, &k); if(op[0] == 'M'){ scanf("%d", &d); update(u, k, d); } else printf("%I64d\n", query(u, k)); } } return 0; }