2333,好6的题号…
嘛,题目大意是维护一些点的连通性及每个联通块中的最大权值,支持的操作有加边,增加某点/联通块/所有点权值,查询某点权值,某联通块/所有点权值.
首先,题目不强制在线,我们可以先将所有的加边操作搞成
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;
}