1. 程式人生 > >【51Nod2004】終結之時

【51Nod2004】終結之時

【題目連結】

【思路要點】

  • 建出 支配樹 ,剩餘的操作均可以通過輕重鏈剖分+線段樹解決。
  • 時間複雜度 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