CF1416D Graph and Queries

CF1416D Graph and Queries

看到这题第一眼就想到时光倒流,但是操作一只能顺序做,这就很困惑了。

但是一个比较好的性质是操作一只会改变点值,操作二只会改变图的形态,启发我们结合时光倒流顺序做。

按照每条边消失的时间可以给边标上边权,我们希望能对答案造成贡献的只有边权 \(\le k\) 的边。这就很有 Kruskal 重构树的感觉,那么把重构树建出来,每次询问可以倍增跳到深度最小的点上,这时候只有这个点的后代能对答案造成贡献。

也就是说我们要维护子树的 max,加上单点修改操作。直接上线段树就可以了。

不用展开就可以看代码了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#define LL long long
using namespace std;
template <typename T>
inline void read(T &x) {
	x = 0; int f = 0; char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
	if(f) x = ~x + 1;
}
const int N = 5e5 + 10;
int n, m, q;
struct Kru {
	int u, v, w;
}kru[N << 1];
int dsu[N], a[N];
int t[N], dot;
int find(int x) {return dsu[x] == x ? x : (dsu[x] = find(dsu[x]));}
vector<int> G[N]; 
void merge(int x, int y, int w) {
	x = find(x), y = find(y);
	if(x == y) return;
	dsu[x] = dsu[y] = ++dot;
	t[dot] = w;
	G[dot].emplace_back(x), G[dot].emplace_back(y);
}
int fa[N][20];
int dfn[N], id[N], dfc, sz[N];
void dfs(int u) {
	dfn[u] = ++dfc, id[dfc] = u, sz[u] = 1;
	for(auto v : G[u]) {
		fa[v][0] = u;
		dfs(v);
		sz[u] += sz[v];
	}
}
int query(int u, int x) {
	for(int i = 18; i >= 0; --i)
		if(fa[u][i] && t[fa[u][i]] >= x) u = fa[u][i];
	return u;
}
int qu[N], tim[N], qtot;
struct SegmentTree {
	#define lc (k << 1)
	#define rc (k << 1 | 1)
	#define mid ((l + r) >> 1)
	int tr[N << 2];
	inline int max(int x, int y) {
		if(a[id[x]] < a[id[y]]) return y;
		else return x;
	}
	inline void update(int k) {tr[k] = max(tr[lc], tr[rc]);}
	void build(int k, int l, int r) {
		if(l == r) return tr[k] = l, void();
		build(lc, l, mid), build(rc, mid + 1, r);
		update(k);
	}
	void modify(int k, int l, int r, int pos) {
		if(l > pos || r < pos) return;
		if(l == r) return ;
		modify(lc, l, mid, pos), modify(rc, mid + 1, r, pos);
		update(k);
	}
	int query(int k, int l, int r, int L, int R) {
		if(l > R || r < L) return 0;
		if(L <= l && r <= R) return tr[k];
		return max(query(lc, l, mid, L, R), query(rc, mid + 1, r, L, R));
	}
	#undef lc
	#undef rc
	#undef mid
}seg;
int main() {
	read(n), read(m), read(q);
	for(int i = 1; i <= n; ++i) 
		read(a[i]);
	for(int i = 1; i <= 5e5; ++i)
		dsu[i] = i;
	for(int i = 1; i <= m; ++i)
		read(kru[i].u), read(kru[i].v), kru[i].w = q;
	for(int i = 1, x, tp; i <= q; ++i){
		read(tp);
		if(tp == 1) read(qu[++qtot]), tim[qtot] = i;
		else read(x), kru[x].w = i;
	}
	sort(kru + 1, kru + m + 1, [](Kru x, Kru y) {return x.w < y.w;});
	dot = n;
	for(int i = m; i >= 1; --i)
		merge(kru[i].u, kru[i].v, kru[i].w);
	for(int i = dot; i >= 1; --i)
		if(!dfn[i]) dfs(i);
	for(int i = 1; i <= 18; ++i)
		for(int j = 1; j <= dot; ++j)
			fa[j][i] = fa[fa[j][i - 1]][i - 1];
	seg.build(1, 1, dot);
	for(int i = 1; i <= qtot; ++i) {
		int x = query(qu[i], tim[i]);
		int p = seg.query(1, 1, dot, dfn[x], dfn[x] + sz[x] - 1);
		printf("%d\n",a[id[p]]); 
		a[id[p]] = 0, seg.modify(1, 1, dot, p);
	}
}
posted @ 2022-12-31 15:05  DCH233  阅读(23)  评论(0编辑  收藏  举报