Connections in Galaxy War ZOJ

点权并查集的反向离线操作

题目大意:有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("
");
        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
",ans[i]); 
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Accepting/p/12660338.html