【51Nod2004】终结之时

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82784966

【题目链接】

【思路要点】

  • 建出 支配树 ,剩余的操作均可以通过轻重链剖分+线段树解决。
  • 时间复杂度 O ( Q L o g 2 N + M ) O(QLog^2N+M)
  • 另外,等到笔者写完可持久化后才发现这个题的可持久化是假的,只需要将之前进行的操作减回去即可,这样做空间复杂度就不会高达 O ( N L o g 2 N ) O(NLog^2N) 了。但可持久化的版本过了,就不重写了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXP = 3e6 + 5;
const int MAXLOG = 17;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct SegmentTree {
	struct Node {
		int lc, rc, tag;
		long long sum;
	} a[MAXP];
	int n, size, version, root[MAXN];
	void build(int &root, int l, int r, int *val, int *p) {
		if (root == 0) root = ++size;
		if (l == r) {
			a[root].sum = val[p[l]];
			return;
		}
		int mid = (l + r) / 2;
		build(a[root].lc, l, mid, val, p);
		build(a[root].rc, mid + 1, r, val, p);
		a[root].sum = a[a[root].lc].sum + a[a[root].rc].sum;
	}
	void init(int x, int *val, int *p) {
		n = x; size = 0;
		build(root[0], 1, n, val, p);
	}
	int modify(int root, int l, int r, int ql, int qr, int delta) {
		int ans = ++size;
		a[ans] = a[root];
		a[ans].sum += (qr - ql + 1ll) * delta;
		if (l == ql && r == qr) {
			a[ans].tag += delta;
			return ans;
		}
		int mid = (l + r) / 2;
		if (mid >= ql) a[ans].lc = modify(a[root].lc, l, mid, ql, min(mid, qr), delta);
		if (mid + 1 <= qr) a[ans].rc = modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, delta);
		return ans;
	}
	void advance() {
		version++;
		root[version] = root[version - 1];
	}
	void modify(int l, int r, int delta, bool stay) {
		version++;
		root[version] = modify(root[version - 1], 1, n, l, r, delta);
		if (stay) {
			root[version - 1] = root[version];
			version--;
		}
	}
	long long query(int root, int l, int r, int ql, int qr) {
		if (l == ql && r == qr) return a[root].sum;
		long long ans = (qr - ql + 1ll) * a[root].tag;
		int mid = (l + r) / 2;
		if (mid >= ql) ans += query(a[root].lc, l, mid, ql, min(mid, qr));
		if (mid + 1 <= qr) ans += query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
		return ans;
	}
	long long query(int ql, int qr) {
		return query(root[version], 1, n, ql, qr);
	}
	void reverse(int cnt) {
		if (version >= cnt) version -= cnt;
		else version = 0;
	}
} ST;
int sdom[MAXN], idom[MAXN], val[MAXN];
int n, m, timer, dfn[MAXN], rit[MAXN], depth[MAXN];
int size[MAXN], son[MAXN], p[MAXN], up[MAXN];
int f[MAXN], father[MAXN][MAXLOG], home[MAXN];
vector <int> a[MAXN], b[MAXN], c[MAXN];
void mfs(int pos) {
	dfn[pos] = ++timer, p[timer] = pos;
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (dfn[a[pos][i]] == 0) {
			father[a[pos][i]][0] = pos;
			mfs(a[pos][i]);
		}
}
void dfs(int pos, int fa) {
	size[pos] = 1, son[pos] = 0;
	depth[pos] = depth[fa] + 1;
	father[pos][0] = fa;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	for (unsigned i = 0; i < a[pos].size(); i++) {
		dfs(a[pos][i], pos);
		size[pos] += size[a[pos][i]];
		if (size[a[pos][i]] > size[son[pos]]) son[pos] = a[pos][i];
	}
}
void efs(int pos, int from) {
	up[pos] = from;
	dfn[pos] = ++timer, p[timer] = pos;
	if (son[pos]) efs(son[pos], from);
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != son[pos]) efs(a[pos][i], a[pos][i]);
	rit[pos] = timer;
}
int F(int x) {
	if (x == f[x]) return x;
	int tmp = f[x];
	f[x] = F(tmp);
	if (sdom[home[tmp]] < sdom[home[x]]) home[x] = home[tmp];
	return f[x];
}
int gethome(int pos) {
	F(pos);
	return home[pos];
}
int lca(int x, int y) {
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
bool cmp(int x, int y) {
	return dfn[x] < dfn[y];
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= n; i++)
		read(val[i]);
	for (int i = 1; i <= m; i++) {
		int x, y; read(x), read(y);
		a[x].push_back(y);
		b[y].push_back(x);
	}
	mfs(1);
	for (int i = 1; i <= timer; i++) {
		sdom[p[i]] = i;
		home[p[i]] = f[p[i]] = p[i];
	}
	for (int i = timer; i >= 2; i--) {
		int pos = p[i];
		for (unsigned i = 0; i < b[pos].size(); i++)
			if (dfn[b[pos][i]]) chkmin(sdom[pos], sdom[gethome(b[pos][i])]);
		c[sdom[pos]].push_back(pos);
		f[pos] = father[pos][0];
		int tmp = dfn[father[pos][0]];
		for (unsigned i = 0; i < c[tmp].size(); i++) {
			int tnp = gethome(c[tmp][i]);
			if (sdom[tnp] == tmp) idom[c[tmp][i]] = tmp;
			else idom[c[tmp][i]] = dfn[tnp];
		}
		c[tmp].clear();
	}
	for (int i = 1; i <= n; i++)
		a[i].clear();
	for (int i = 2; i <= timer; i++) {
		int pos = p[i];
		if (idom[pos] == sdom[pos]) idom[pos] = p[idom[pos]];
		else idom[pos] = idom[p[idom[pos]]];
		a[idom[pos]].push_back(pos);
	}
	timer = 0;
	memset(dfn, 0, sizeof(dfn));
	dfs(1, 0);
	efs(1, 1);
	ST.init(n, val, p);
	int q; read(q);
	while (q--) {
		char opt = getchar();
		while (opt != 'C' && opt != 'Q' && opt != 'R') opt = getchar();
		if (opt == 'C') {
			int type, x, y;
			read(type), read(x), read(y);
			if (dfn[x] == 0) {
				ST.advance();
				continue;
			}
			if (type == 1) ST.modify(dfn[x], dfn[x], y, false);
			if (type == 2) ST.modify(dfn[x], rit[x], y, false);
			if (type == 3) {
				bool tmp = false;
				while (x != 0) {
					ST.modify(dfn[up[x]], dfn[x], y, tmp);
					x = father[up[x]][0];
					tmp = true;
				}
			}
		}
		if (opt == 'Q') {
			int type, x;
			read(type), read(x);
			if (type == 1) {
				if (dfn[x] == 0) writeln(0);
				else writeln(ST.query(dfn[x], rit[x]));
			}
			if (type == 2) {
				if (dfn[x] == 0) writeln(0);
				else {
					long long ans = 0;
					while (x != 0) {
						ans += ST.query(dfn[up[x]], dfn[x]);
						x = father[up[x]][0];
					}
					writeln(ans);
				}
			}
			if (type == 3) {
				static int pos[MAXN];
				for (int i = 1; i <= x; i++)
					read(pos[i]);
				sort(pos + 1, pos + x + 1, cmp);
				if (dfn[pos[1]] == 0) writeln(0);
				else {
					long long ans = 0;
					for (int i = 1; i <= x; i++) {
						int tmp = pos[i];
						while (tmp != 0) {
							ans += ST.query(dfn[up[tmp]], dfn[tmp]);
							tmp = father[up[tmp]][0];
						}
						tmp = lca(pos[i], pos[i - 1]);
						while (tmp != 0) {
							ans -= ST.query(dfn[up[tmp]], dfn[tmp]);
							tmp = father[up[tmp]][0];
						}
					}
					writeln(ans);
				}
			}
		}
		if (opt == 'R') {
			int x; read(x);
			ST.reverse(x);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/82784966