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);
}
}