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; }
没有人不辛苦,只有人不喊疼