BZOJ2333

来源:互联网 发布:超级山猫直升机数据 编辑:程序博客网 时间:2024/05/18 22:43

2333,好6的题号…
嘛,题目大意是维护一些点的连通性及每个联通块中的最大权值,支持的操作有加边,增加某点/联通块/所有点权值,查询某点权值,某联通块/所有点权值.
首先,题目不强制在线,我们可以先将所有的加边操作搞成k(k为最后的联通块个数)条链,顺次打上序号后变成一个序列,可以发现,每个时刻的联通块都是一个连续的序列,于是我们可以用线段树维护最大值
代码(话说为毛加了按轶合并的并查集反而慢那么多…):

#include <bits/stdc++.h>using namespace std;#define For(i,n) for(int i=1;i<=n;i++)const int MAXN=int(3*1e5+5),INF=0x3f3f3f3f;int n,q;int pos[MAXN],ipos[MAXN],a[MAXN];int read(){    int r=0;char c;bool sign=0;    while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));    while(r=r*10+c-'0',isdigit(c=getchar()));    return sign?-r:r;}struct OP {int op,x,y;} op[MAXN];int s,t,v;struct SGT{    SGT *ls,*rs;    int l,r,mid;    int _max,add;    SGT(){};    SGT(int l,int r):l(l),r(r){ls=rs=0;add=0;}    void Build();    void Add(int c) {_max+=c;add+=c;}    void Push_Up() {_max=max(ls->_max,rs->_max);}    void Push_Down() {add?(ls->Add(add),rs->Add(add),add=0):0;}    void Updata1(){        if(l==r) {_max+=v;return;}        Push_Down();        s<=mid?ls->Updata1():rs->Updata1();        Push_Up();    }void Updata(){        if(s<=l && t>=r) {Add(v);return;}        Push_Down();        if(s<=mid) ls->Updata();        if(t> mid) rs->Updata();        Push_Up();    }int Query(){        if(s<=l && t>=r) return _max;        Push_Down();        int _=-INF;        s<=mid?_=max(_,ls->Query()):0;        t> mid?_=max(_,rs->Query()):0;        return _;    }}*root,Node[MAXN<<1];int mp=0;SGT* New(int l,int r){    Node[mp]=SGT(l,r);    return &Node[mp++];}void SGT::Build(){    if(l==r) {_max=a[ipos[l]];return;}    mid=(l+r)>>1;    (ls=New(l,mid))->Build();    (rs=New(mid+1,r))->Build();    Push_Up();}int f[MAXN],rank[MAXN],nxt[MAXN],tai[MAXN];//f,rank:USF;nxt_x:x所连的元素,tai_x:x(联通块的代表元素)中最后的一个元素;void Init_(){    memset(f,0,sizeof(f));    memset(rank,0,sizeof(rank));    memset(nxt,0,sizeof(nxt));    For(i,n) tai[i]=i;}int P(int x) {return !f[x]?x:f[x]=P(f[x]);}void Union(int x,int y){    int fx=P(x),fy=P(y);    if(fx==fy) return;    if(rank[fx]>rank[fy]) swap(fx,fy);    f[fx]=fy;    nxt[tai[fy]]=fx; tai[fy]=tai[fx];//tai_fx之后无意义    rank[fx]==rank[fy]?rank[fy]++:0;}void Init(){    n=read();    For(i,n) a[i]=read();    q=read();    char s[5];    Init_();    For(i,q){        scanf("%s",s);        switch (s[0]){            case 'A':op[i].op=s[1]-'0';op[i].x=read();s[1]!='3'?op[i].y=read():0; break;            case 'F':op[i].op=s[1]-'0'+3;s[1]!='3'?op[i].x=read():0; break;            default:op[i].op=0;op[i].x=read();op[i].y=read();Union(op[i].x,op[i].y);        }    }    int dfn=1;    For(i,n) if(!f[i])        for(int j=i;j;j=nxt[j])            ipos[dfn]=j,pos[j]=dfn++;    (root=New(1,n))->Build();    Init_();}int main(){#ifdef bhiaibogf    freopen("in.in","r",stdin);#endif    Init();    int x;    For(i,q) switch (op[i].op){        case 0:Union(op[i].x,op[i].y); break;        case 1:s=pos[op[i].x],v=op[i].y;root->Updata1(); break;        case 2:x=P(op[i].x);s=pos[x],t=pos[tai[x]],v=op[i].y;root->Updata(); break;        case 3:s=1,t=n,v=op[i].x;root->Updata(); break;        case 4:s=t=pos[op[i].x];printf("%d\n",root->Query()); break;        case 5:x=P(op[i].x);s=pos[x],t=pos[tai[x]];printf("%d\n",root->Query()); break;        case 6:s=1,t=n;printf("%d\n",root->Query()); break;    }    return 0;}

当然,在线算法也不难写…
我们只需要一个可并堆,斜堆好啊…对于全局最大值,我们可以再开个set
斜堆就是在合并两个堆A,B(不妨设A的堆顶元素大)时,将A的右子树与B合并作为新的右子树,并将左右子树交换,期望是O(logn)的.注意标记要从堆顶向下传…
代码:

#include <bits/stdc++.h>using namespace std;#define Insert(x) _max.insert(x)#define Erase(x) _max.erase(_max.find(x))#define ls s[0]#define rs s[1]#define hu heap[u]#define hv heap[v]const int MAXN=int(3*1e5+5),INF=0x3f3f3f3f;int n,_add;multiset<int> _max;int read(){    int r=0;char c;bool sign=0;    while(c=getchar(),c=='-'?sign=1:0,!isdigit(c));    while(r=r*10+c-'0',isdigit(c=getchar()));    return sign?-r:r;}struct Node{    Node *s[2],*f;    int x,add;    Node(){};    Node(int x);    Node* Link(int d,Node *p);    void Add(int c);    void Push_Down();    Node* P();    int Top();    Node* Remove();}*null=new Node(-INF),heap[MAXN],*p,*q;Node* Merge(Node *p,Node *q){    if(p==null) return q;    if(q==null) return p;    if(p->x<q->x) swap(p,q);    p->Push_Down();    p->Link(1,Merge(p->rs,q));    swap(p->ls,p->rs);    return p;}Node::Node(int x):x(x){    Insert(x);    add=0;    ls=rs=f=null;}Node* Node::Link(int d,Node *p){    s[d]=p;    return p==null?this:p->f=this;}void Node::Add(int c){    if(this==null) return;    add+=c;x+=c;}void Node::Push_Down(){    if(this==null) return;    f->Push_Down();    add?(ls->Add(add),rs->Add(add),add=0):0;}Node* Node::P(){    Node *p;    for(p=this;p->f!=null;p=p->f);    return p;}int Node::Top(){    return P()->x;}Node* Node::Remove(){    Push_Down();    p=f,q=Merge(ls,rs);    f=ls=rs=null;    if(p==null) return q->f=null,q;    p->Link(p->rs==this,q);    return p->P();}int u,v;void A1(){    u=read();v=read();    Erase(hu.Top());    hu.Push_Down();    hu.x+=v;    Insert(Merge(&hu,hu.Remove())->Top());}void A2(){    u=read();v=read();    p=hu.P();    Erase(p->x);    p->Add(v);    Insert(p->x);}void U(){    u=read();v=read();    p=hu.P(),q=hv.P();    if(p!=q) Merge(p,q)==p?Erase(q->x):Erase(p->x);}int main(){#ifdef bhiaibogf    freopen("in.in","r",stdin);#endif    n=read();    for(int i=1;i<=n;i++) heap[i]=Node(read());    int q=read();char op[5];    while(q--){        scanf("%s",op);        switch (op[0]){            case 'A':switch (op[1]){                case '1':A1();break; case '2':A2();break; case '3':_add+=read();break;            }break;            case 'F':switch (op[1]){                case '1':u=read();hu.Push_Down();printf("%d\n",hu.x+_add);break;                case '2':u=read();printf("%d\n",hu.Top()+_add);break;                case '3':printf("%d\n",*--_max.find(INF)+_add);break;            }break;            default:U();        }    }    return 0;}
0 0