题目
思路
引用某大佬的一句话:因为 LCT 是垃圾,所以我们不考虑它。不好意思搞错了,是这一句:
对于删边,我们的处理工具很有限。要么是对询问分块,要么是删边转化为加边。
所以这道题我们只好将删边转换为加边。这样想的原因还是 维护连通块。两个连通块通过加边来合成。这玩意儿不像线段树么?
然后,比较套路的,想到类似于克鲁斯卡尔重构树的东西。想到对子树进行操作。想到线段树维护 d f n dfn dfn 的 c o m m o n t r i c k \rm common\; trick commontrick 。然后意识到 O ( n log n ) \mathcal O(n\log n) O(nlogn) 做完了。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
const int MaxN = 200005;
int n, p[MaxN];
int son[MaxN<<1][2];
namespace UFS{
int fa[MaxN<<1], totNode;
inline int findFa(int a){
if(a != fa[a])
fa[a] = findFa(fa[a]);
return fa[a];
}
void init(){
for(int i=0; i<(MaxN<<1); ++i)
fa[i] = i; // single
totNode = 0; // clear
}
inline void merg(int a,int b){
a = findFa(a), b = findFa(b);
if(a == b) return ;
int x = ++ totNode;
son[x][0] = a, fa[a] = x;
son[x][1] = b, fa[b] = x;
}
}
int st[MaxN<<1], ed[MaxN<<1];
int dfn, num[MaxN];
void dfs(int x){
st[x] = dfn+1; // hesitate
if(!son[x][0]) // a leaf
num[++ dfn] = p[x];
else{
dfs(son[x][0]);
dfs(son[x][1]);
}
ed[x] = dfn;
}
namespace SgTree{
inline int id(int l,int r){
return (l+r)|(l!=r);
}
int v[MaxN<<1];
void pushUp(int l,int r){
int m = (l+r)>>1, o = id(l,r);
v[o] = v[id(m+1,r)];
if(num[v[o]] < num[v[id(l,m)]])
v[o] = v[id(l,m)];
}
void build(int l=1,int r=n){
if(l == r){
v[id(l,r)] = l;
return ;
}
build(l,(l+r)>>1);
build((l+r)/2+1,r);
pushUp(l,r);
}
int query(int ql,int qr,int l=1,int r=n){
if(ql <= l && r <= qr)
return v[id(l,r)];
int m = (l+r)>>1;
if(qr <= m) return query(ql,qr,l,m);
if(m < ql) return query(ql,qr,m+1,r);
int las = query(ql,qr,m+1,r);
int ras = query(ql,qr,l,m);
if(num[las] > num[ras])
return las;
else return ras; // find max
}
void modify(int qid,int l=1,int r=n){
if(l == r){
num[qid] = 0; return ;
}
if(qid <= ((l+r)>>1))
modify(qid,l,(l+r)>>1);
else modify(qid,(l+r)/2+1,r);
pushUp(l,r);
}
}
const int MaxQ = 500005;
struct CMD{
int opt, x;
};
CMD cmd[MaxQ];
const int MaxM = 300005;
struct Edge{
int zxy, sxy;
};
Edge e[MaxM];
bool fucked[MaxM];
int main(){
UFS::init(); // init all
UFS::totNode = n = readint();
int m = readint();
int q = readint();
for(int i=1; i<=n; ++i)
p[i] = readint();
for(int i=1; i<=m; ++i){
e[i].zxy = readint();
e[i].sxy = readint();
}
for(int i=1; i<=q; ++i){
cmd[i].opt = readint();
cmd[i].x = readint();
if(cmd[i].opt == 2)
fucked[cmd[i].x] = 1;
}
for(int i=1; i<=m; ++i){
if(fucked[i]) continue;
UFS::merg(e[i].zxy,e[i].sxy);
}
for(int i=q; i>=1; --i){
if(cmd[i].opt == 2)
UFS::merg(
e[cmd[i].x].zxy,
e[cmd[i].x].sxy
);
else cmd[i].x = UFS::
findFa(cmd[i].x);
}
for(int i=1; i<=UFS::totNode; ++i)
if(UFS::findFa(i) == i)
dfs(i); // all root
SgTree::build();
for(int i=1,x; i<=q; ++i){
if(cmd[i].opt == 2)
continue;
x = SgTree::query(
st[cmd[i].x],
ed[cmd[i].x]
);
printf("%d\n",num[x]);
SgTree::modify(x);
}
return 0;
}