点权并查集的反向离线操作
题目大意:有n个stars,每一个都一定的“颜值”。然后stars与stars之间可以相连,query c表示再与c相连的stars中,颜值比c高的,stars的标号,如果有多个, 输出最小那一个。destroy x y,表示将x和y这条边销毁掉。
题解:并查集只能加边不能删边,所以我们可以倒着来,那么每个destroy就相当于join了。然后就是套上一个点权并查集(不会的自己学)。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+7;
const ll MAX=100000;
ll Hash=1e4;
map<ll,bool>mp;
ll val[N];
ll fa[N];
bool mark[N];
ll l[N],r[N];
ll l1[N],r1[N];
ll ans[N];
ll find(ll x){
return fa[x]==x? x:fa[x]=find(fa[x]);
}
void unite(ll x,ll y){
ll fx=find(x);
ll fy=find(y);
if(val[fx]>val[fy]) fa[fy]=fx;
else if(val[fx]<val[fy]) fa[fx]=fy;
else if(fx>fy) fa[fx]=fy;
else fa[fy]=fx;
}
int main(){
ll n,time=0;
ios::sync_with_stdio(0);
while(cin>>n){
if(time++) printf("\n");
mp.clear();
for(ll i=0;i<=100000;i++){
fa[i]=i;
mark[i]=0;
}
for(ll i=0;i<n;i++) cin>>val[i];
ll x;cin>>x;
ll a,b;
for(ll i=1;i<=x;i++){
cin>>a>>b;
if(a>b) swap(a,b);
l1[i]=a;r1[i]=b;
}
ll m;cin>>m;
string s;
for(ll i=1;i<=m;i++){
cin>>s;
if(s=="destroy"){
cin>>a>>b;
mark[i]=1;
if(a>b) swap(a,b);
l[i]=a;r[i]=b;
mp[l[i]*Hash+r[i]]=1;//每个destroy用Hash记录一下
}
else cin>>l[i];
}
for(ll i=1;i<=x;i++){
if(!mp[l1[i]*Hash+r1[i]]) {
unite(l1[i],r1[i]);
}
}
ll cnt=0;
for(ll i=m;i>=1;i--){
if(mark[i]) {
unite(l[i],r[i]);
}
else{
ll c=find(l[i]);
if(val[c]>val[l[i]]) ans[++cnt]=c;
else ans[++cnt]=-1;
}
}
for(ll i=cnt;i>=1;i--) printf("%lld\n",ans[i]);
}
return 0;
}