题目
题意:
给定一张无向图,n个点,m条边。每个点都有点权,点权互不相同,有两种操作。
操作1:1 v,输出v点所在的连通块的点权最大值,并将那个点的权值置为0。
操作2:2 i,将第i条边删去。
1
≤
n
≤
2
e
5
,
1
≤
m
≤
3
e
5
,
1
≤
q
≤
5
e
5
。
1≤n≤2e5,1≤m≤3e5,1≤q≤5e5。
1≤n≤2e5,1≤m≤3e5,1≤q≤5e5。
分析:
这种带有删边的题目一般都会考虑从后往前加边,但是这道题每次输出答案的时候同时修改了点权,所以从后往前似乎无法操作。再考虑如果没有删边的话,就是维护一个并查集,每个并查集再维护一个set,按点权大小排序,每次访问时就拿出最大的输出然后修改即可。
那么其实删边是可以通过可撤销并查集来完成的,我们先把那些没有删去的边加入,再从后往前加入那些被删去的边,这样每次有删边操作时,我们只要把最新的操作撤销即可。考虑合并两个集合,那就把set的大小小的那一个都放到大的那里去就好了,撤销时遍历一下删去即可。
#include <iostream>
#include <set>
#include <vector>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int maxn = 5e5+5;
struct node{
int id,val;
node(int a,int b)
{
id = a;
val = b;
}
bool operator<(const node&n)const
{
if( val == n.val ) return id < n.id;
return val > n.val;
}
};
set<node> s[maxn];
int parent[maxn],v[maxn];
vector<pii> tmp;
int vis[maxn];
pii e[maxn];
struct query{
int op,v;
}q[maxn];
int find(int p)
{
if( p == parent[p] ) return p;
return find(parent[p]);
}
void done(pii v)
{
int fx = find(v.fi),fy = find(v.se);
if( fx == fy )
{
tmp.push_back(mp(-1,-1));
return;
}
if( s[fx].size() > s[fy].size() ) swap(fx,fy);
tmp.push_back(mp(fx,fy));
set<node>::iterator it;
for (it = s[fx].begin(); it != s[fx].end(); it++)
{
s[fy].insert(*it);
}
parent[fx] = fy;
}
void undone()
{
pii z = tmp.back();
tmp.pop_back();
if( z.fi == -1 ) return;
set<node>::iterator it;
for (it = s[z.fi].begin(); it != s[z.fi].end(); it++)
{
node t = *it;
if( v[t.id] == 0 ) continue;
s[z.se].erase(*it);
}
parent[z.fi] = z.fi;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n,m,qx;
cin >> n >> m >> qx;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
parent[i] = i;
s[i].insert(node(i,v[i]));
}
for (int i = 1; i <= m; i++) cin >> e[i].fi >> e[i].se;
for (int i = 1; i <= qx; i++)
{
cin >> q[i].op >> q[i].v;
if( q[i].op == 2 ) vis[q[i].v] = 1;
}
for (int i = 1; i <= m; i++)
if( vis[i] == 0 ) done(e[i]);
for (int i = qx; i >= 1; i--)
if( q[i].op == 2 ) done(e[q[i].v]);
for (int i = 1; i <= qx; i++)
{
if( q[i].op == 1 )
{
int fx = find(q[i].v);
while( s[fx].size() > 0 && v[(*s[fx].begin()).id] == 0 ) s[fx].erase(s[fx].begin());
if( s[fx].size() == 0 ) cout << 0 << '\n';
else
{
node t = *s[fx].begin();
cout << v[t.id] << '\n';
v[t.id] = 0;
}
}else undone();
}
return 0;
}