一道不错的有关于各种tag我们熟练维护的题
首先这题可以1个log的左偏树做,但是考虑到细节较多我们用两个log的启发式合并来写,当然你也可以用splay可以自适应做到1个log。
我们这里的splay换为set方便维护
首先我们单点加和整体加都可以非常方便的维护,于是我们只剩下对于一个联通的集合加一个数,
这是一个经典的套路我们对于这个集合维护一个tag,然后我们两个合并的时候用一个tag减去另一个的tag,然后更新它新的权值,相当于这么一个tag的dat,然后update以后我们就可以用启发式合并!
剩下就是一个细节的问题,我们只需要用并查集维护连通性,每次从儿子像父亲连边,同时合并就可以了,也就是并查集的过程中哪个部分size大我们就钦定往它上连边!
维护全局最大是还需要一个全局set,大概就可以了,注意我们这里的set是有重复的,即都需要使用multiset!
代码:

#include<bits/stdc++.h>
#define fgx cerr<<"-----------------------"<<endl
#define LL long long
#define DB double
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    const int BS=(1<<23)+5; int Top=0;
    char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
    char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    void flush(){fwrite(OT,1,OS-OT,stdout),OS=OT;}
    void Putchar(char c){*OS++ =c;if(OS==fin)flush();}
    void write(LL x){
        if(!x){Putchar('0'),Putchar('\n'); return;} if(x<0) x=-x,Putchar('-');
        while(x) SS[++Top]=x%10,x/=10;
        while(Top) Putchar(SS[Top]+'0'),--Top; Putchar('\n');
    }
    inline LL read(){
        LL nm=0; bool fh=true; char cw=getchar();
        for(;!isdigit(cw);cw=getchar()) fh^=(cw=='-');
        for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
        return fh?nm:-nm;
    }
} using namespace IO;
#define M 300020
#define vl first
#define ps second
#define IT multiset<LL>::iterator
#define ITP multiset<pair<LL,int> >::iterator
int n,m,fa[M]; LL val[M],tg[M],alltg;
multiset<pair<LL,int> >s[M]; multiset<LL>S;
inline LL gtmx(int f){ITP it=s[f].end();it--; return (LL)(*it).vl+tg[f];}
inline void ins(LL x){S.insert(x);}
inline void del(LL x){IT it=S.lower_bound(x); S.erase(it);}
inline int find(int x){return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
int main(){
    n=read();
    for(int i=1;i<=n;i++) val[i]=read(),s[i].insert(mp(val[i],i)),fa[i]=i,ins(gtmx(i));
    m=read();
    for(int i=1;i<=m;i++){
        char ch[15]; scanf("%s",ch);
        if(ch[0]=='U'){
            int x=read(),y=read(),fx=find(x),fy=find(y); if(fx==fy) continue;
            if(s[fx].size()>s[fy].size()) swap(fx,fy); del(gtmx(fx)),del(gtmx(fy));
            for(ITP it=s[fx].begin();it!=s[fx].end();it++){int nd=(*it).ps; val[nd]+=tg[fx]-tg[fy],s[fy].insert(mp(val[nd],nd));}
            s[fx].clear(),tg[fx]=0,fa[fx]=fy,ins(gtmx(fy));
        } else if(ch[0]=='A'&&ch[1]=='1'){
            int x=read(),y=read(),fx=find(x); del(gtmx(fx));
            ITP it=s[fx].lower_bound(mp(val[x],x)); s[fx].erase(it);
            val[x]+=(LL)y,s[fx].insert(mp(val[x],x)),ins(gtmx(fx));
        } else if(ch[0]=='A'&&ch[1]=='2'){
            int x=read(),y=read(),fx=find(x);
            del(gtmx(fx)),tg[fx]+=(LL)y,ins(gtmx(fx));
        } else if(ch[0]=='A'&&ch[1]=='3'){
            int y=read(); alltg+=(LL)y;
        } else if(ch[0]=='F'&&ch[1]=='1'){
            int x=read(),fx=find(x);
            write(val[x]+tg[fx]+alltg);
        } else if(ch[0]=='F'&&ch[1]=='2'){
            int x=read(),fx=find(x); ITP it=s[fx].end();it--;
            write((LL)(*it).vl+tg[fx]+alltg);
        } else{
            IT it=S.end();it--; write((LL)(*it)+alltg);
        }
    } flush();
    return 0;
}