NC20282 棘手的操作(启发式合并)

这道题可以使用启发式合并和延迟的策略来做

首先我们发现第一个操作就是将两个集合合并,要在合理的复杂度之内做到此事,启发式合并是个好办法

其次,因为我们需要查询的是最大值,因此用堆来维护也比较方便,但是现在有个问题,因为一些权值会被改变

而堆不能指定元素删除,因此如果要维护这些值,暴力的做法是把这个值找出来再删掉,这样显然复杂度不过关。

这里有个思路是延迟删除,给删除的值打标记,表示他被删除了,因为我们求得是最大值,所以当前最大值如果被打标记了,那就跳过这个值继续

这样得复杂度是过关的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=6e5+10;
const int mod=998244353;
struct node{
    priority_queue<int> del,add;
    void ph1(int x){
        add.push(x);
    }
    void ph2(int x){
        del.push(x);
    }
    int top(){
        while(del.size()&&del.top()==add.top())
            del.pop(),add.pop();
        return add.top();
    }
}s[N],all;
int p[N],tag[N],alltag;
int find(int x){
    if(x!=p[x]){
        p[x]=find(p[x]);
    }
    return p[x];
}
int a[N];
vector<int> num[N];
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int i;
    for(i=1;i<=n;i++){
        cin>>a[i];
        p[i]=i;
        num[i].push_back(i);
        s[i].ph1(a[i]);
        all.ph1(a[i]);
    }
    int q;
    cin>>q;
    while(q--){
        string opt;
        cin>>opt;
        if(opt=="U"){
            int x,y;
            cin>>x>>y;
            int pa=find(x);
            int pb=find(y);
            if(pa==pb)
                continue;
            all.ph2(s[pa].top()+tag[pa]);
            all.ph2(s[pb].top()+tag[pb]);
            if(num[pa].size()<num[pb].size()){
                swap(pa,pb);
            }
            for(auto d:num[pb]){
                p[d]=pa;
                a[d]+=tag[pb];
                a[d]-=tag[pa];
                s[pa].ph1(a[d]);
                num[pa].push_back(d);
            }
            all.ph1(s[pa].top()+tag[pa]);
        }
        else if(opt=="A1"){
            int x,v;
            cin>>x>>v;
            int pa=find(x);
            all.ph2(s[pa].top()+tag[pa]);
            s[pa].ph2(a[x]);
            a[x]+=v;
            s[pa].ph1(a[x]);
            all.ph1(s[pa].top()+tag[pa]);
        }
        else if(opt=="A2"){
            int x,v;
            cin>>x>>v;
            int pa=find(x);
            all.ph2(s[pa].top()+tag[pa]);
            tag[pa]+=v;
            all.ph1(s[pa].top()+tag[pa]);
        }
        else if(opt=="A3"){
            int v;
            cin>>v;
            alltag+=v;
        }
        else if(opt=="F1"){
            int x;
            cin>>x;
            int pa=find(x);
            cout<<a[x]+tag[pa]+alltag<<endl;
        }
        else if(opt=="F2"){
            int x;
            cin>>x;
            int pa=find(x);
            cout<<s[pa].top()+tag[pa]+alltag<<endl;
        }
        else if(opt=="F3"){
            cout<<all.top()+alltag<<endl;
        }
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14609486.html