• HDU 5957 Query on a graph


    HDU 5957 Query on a graph

    2016ACM/ICPC亚洲区沈阳站

    题意

    • (N(N le 10^5))个点,(N)条边的连通图。
    • (M le 10^5)操作:
    1. (MODIFY u k d,k le 2):距离点(u)不超过(k)的点的权值都加上(d)
    2. (QUERY u k):询问距离(d)不超过(k)的点权和。

    思路

    • 图的形状时一个环和若干树枝构成。
    • 考虑(k=1)时,分两种情况讨论:
    1. (u)在环上,则需要累加环上相邻两点权值,以及树枝上深度为1的所有点的权值,并且这些点的bfs序是连续的,那么显然可以用线段树维护权值和。
    2. (u)不在环上时,累加父亲节点的权值以及树枝深度为1的点权。
    • (Q1(u))表示距离(u)不超过1的权值和。
    • (k=2)时,树枝上距离为2的点的bfs序也是连续的,所以同样用线段树维护,若(u)不在环上,累加上(Q1(f_u)-w_u)即可;若(u)在环上,求出(Q1(v_1)+Q1(v_2)-2w_u)(v_1、v_2)表示换上与(u)相邻的点,显然(u)被重复计数两次。
    • 当环的长度分别为3、4时,(Q1(v_1)、Q2(v_2))存在交集,需要扣除重复计数的值。
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ul;
    #define sz(x) ((int)(x).size())
    #define rep(i,l,r) for(int i=(l),I=(r);i<I;++i)
    //-------head-------
    const int N = 1e5 + 7;
    #define ls ((t)<<1)
    #define rs ((t)<<1|1)
    ll sum[N << 2], add[N << 2];
    inline void up(int t) {
    	sum[t] = sum[ls] + sum[rs];
    }
    inline void down(int t, int l, int r) {
    	if (add[t] != 0) {
    		int m = (l + r) >> 1;
    		sum[ls] += add[t] * (m - l + 1), add[ls] += add[t];
    		sum[rs] += add[t] * (r - m), add[rs] += add[t];
    		add[t] = 0;
    	}
    }
    void build(int t, int l, int r) {
    	sum[t] = add[t] = 0;
    	if (l < r) {
    		int m = (l + r) >> 1;
    		build(ls, l, m), build(rs, m + 1, r);
    	}
    }
    inline void upd(int t, int l, int r, int L, int R, ll v) {
    	if (R < l || r < L || L > R)
    		return ;
    	if (L <= l && r <= R) {
    		sum[t] += (r - l + 1) * v, add[t] += v;
    		return ;
    	}
    	down(t, l, r);
    	int m = (l + r) >> 1;
    	upd(ls, l, m, L, R, v), upd(rs, m + 1, r, L, R, v);
    	up(t);
    }
    inline ll qry(int t, int l, int r, int L, int R) {
    	if (R < l || r < L || L > R)
    		return 0;
    	if (L <= l && r <= R)
    		return sum[t];
    	down(t, l, r);
    	int m = (l + r) >> 1;
    	ll ret = qry(ls, l, m, L, R) + qry(rs, m + 1, r, L, R);
    	up(t);
    	return ret;
    }
    int n, q, tot, f[N], pos[N], deg[N], L[N][3], R[N][3];
    vector<int> cir, e[N];
    void bfs() {
    	queue<int> que;
    	rep(i, 1, n + 1)
    		if (deg[i] == 1)
    			que.push(i);
    	while (!que.empty()) {
    		int u = que.front();
    		que.pop();
    		rep(i, 0, sz(e[u])) {
    			int v = e[u][i];
    			--deg[v];
    			if (deg[v] == 1)
    				que.push(v);
    		}
    	}
    	rep(i, 1, n + 1)
    		deg[i] = (deg[i] == 2);
    	cir.clear();
    	rep(i, 1, n + 1)
    		if (deg[i]) {
    			int u = i;
    			do {
    				rep(j, 0, sz(e[u])) {
    					int v = e[u][j];
    					if (deg[v] && (cir.empty() || v != cir.back())) {
    						pos[u] = sz(cir);
    						cir.push_back(u);
    						u = v;
    						break;
    					}
    				}
    			} while (u != i);
    			break;
    		}
    }
    int que[N];
    void BFS(int s) {
    	int h = 0, t = 0;
    	que[t++] = s, f[s] = -1;
    	while (h < t) {
    		int u = que[h++];
    		L[u][0] = R[u][0] = ++tot;
    		L[u][1] = L[u][2] = n + 1, R[u][1] = R[u][2] = 0;
    		rep(i, 0, sz(e[u])) {
    			int v = e[u][i];
    			if (v == f[u] || deg[v])
    				continue;
    			f[v] = u, que[t++] = v;
    		}
    	}
    	for (int i = t - 1; i > 0; --i) {
    		int v = que[i];
    		int u = f[v];
    		L[u][1] = min(L[u][1], L[v][0]), R[u][1] = max(R[u][1], R[v][0]);
    		u = f[u];
    		if (u == -1)
    			continue;
    		L[u][2] = min(L[u][2], L[v][0]), R[u][2] = max(R[u][2], R[v][0]);
    	}
    	//    printf("u = %d, ", u);
    	//    rep(i, 0, 3) printf("(%d, %d) ", L[u][i], R[u][i]);puts("");
    }
    char op[20];
    inline ll Q0(int u) {
    	return qry(1, 0, tot, L[u][0], R[u][0]);
    }
    inline ll Q1(int u) {
    	ll ans = Q0(u) + qry(1, 0, tot, L[u][1], R[u][1]);
    	if (deg[u]) {
    		ans += Q0(cir[(pos[u] + 1) % sz(cir)]);
    		ans += Q0(cir[(pos[u] - 1 + sz(cir)) % sz(cir)]);
    	} else {
    		ans += Q0(f[u]);
    	}
    	return ans;
    }
    inline void A0(int u, ll v) {
    	upd(1, 0, tot, L[u][0], R[u][0], v);
    }
    inline void A1(int u, ll v) {
    	A0(u, v), upd(1, 0, tot, L[u][1], R[u][1], v);
    	if (deg[u]) {
    		A0(cir[(pos[u] + 1) % sz(cir)], v);
    		A0(cir[(pos[u] - 1 + sz(cir)) % sz(cir)], v);
    	} else {
    		A0(f[u], v);
    	}
    }
    int main() {
    	int T;
    	scanf("%d", &T);
    	rep(cas, 0, T) {
    		scanf("%d", &n);
    		rep(i, 1, n + 1)
    			deg[i] = 0, e[i].clear();
    		rep(i, 0, n) {
    			int u, v;
    			scanf("%d%d", &u, &v);
    			++deg[u], ++deg[v];
    			e[u].push_back(v), e[v].push_back(u);
    		}
    		bfs();
    		tot = 0;
    		rep(i, 1, n + 1) 
    			if (deg[i])
    				BFS(i);
    		build(1, 0, tot);
    		scanf("%d", &q);
    		rep(_q, 0, q) {
    			scanf(" %s", op);
    			if (op[0] == 'M') {
    				int u, k, d;
    				scanf("%d%d%d", &u, &k, &d);
    				if (k == 0) {
    					A0(u, d);
    				} else if (k == 1) {
    					A1(u, d);
    				} else if (k == 2) {
    					A0(u, d), upd(1, 0, tot, L[u][1], R[u][1], d), upd(1, 0, tot, L[u][2], R[u][2], d);
    					if (deg[u]) {
    						int v1 = cir[(pos[u] + 1) % sz(cir)];
    						int v2 = cir[(pos[u] - 1 + sz(cir)) % sz(cir)];
    						A1(v1, d), A1(v2, d), A0(u, -2 * d);
    						if (sz(cir) == 3) {
    							A0(v1, -d), A0(v2, -d);
    						} else if (sz(cir) == 4) {
    							A0(cir[(pos[u] + 2) % sz(cir)], -d);
    						}
    					} else {
    						A1(f[u], d), A0(u, -d);
    					}
    				}
    			} else {
    				int u, k;
    				scanf("%d%d", &u, &k);
    				ll ans = 0;
    				if (k == 0) {
    					ans = Q0(u);
    				} else if (k == 1) {
    					ans = Q1(u);
    				} else if(k == 2) {
    					ans = Q0(u) + qry(1, 0, tot, L[u][1], R[u][1]) + qry(1, 0, tot, L[u][2], R[u][2]);
    					if (deg[u]) {
    						int v1 = cir[(pos[u] + 1) % sz(cir)];
    						int v2 = cir[(pos[u] - 1 + sz(cir)) % sz(cir)];
    						ans += Q1(v1) + Q1(v2) - 2ll * Q0(u);
    						if (sz(cir) == 3) {
    							ans -= Q0(v1) + Q0(v2);
    						} else if (sz(cir) == 4) {
    							ans -= Q0(cir[(pos[u] + 2) % sz(cir)]);
    						}
    					} else {
    						ans += Q1(f[u]) - Q0(u);
    					}
    				}
    				printf("%lld
    ", ans);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    移动app测试
    centos7中tomcat安装步骤
    linux下搭建数据库
    Linux 学习笔记
    vi编辑器 使用表
    python-Xml 实战
    python-Excel 实战
    手写HashMap
    volatile关键字解析
    两个栈实现队列——优化版
  • 原文地址:https://www.cnblogs.com/mcginn/p/6028504.html
Copyright © 2020-2023  润新知