BZOJ2333
来源:互联网 发布:超级山猫直升机数据 编辑:程序博客网 时间:2024/05/18 22:43
2333,好6的题号…
嘛,题目大意是维护一些点的连通性及每个联通块中的最大权值,支持的操作有加边,增加某点/联通块/所有点权值,查询某点权值,某联通块/所有点权值.
首先,题目不强制在线,我们可以先将所有的加边操作搞成
代码(话说为毛加了按轶合并的并查集反而慢那么多…):
#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合并作为新的右子树,并将左右子树交换,期望是
代码:
#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
- BZOJ2333
- bzoj2333
- bzoj2333: [SCOI2011]棘手的操作
- BZOJ2333: [SCOI2011]棘手的操作
- bzoj2333 [SCOI2011]棘手的操作
- bzoj2333[SCOI2011]棘手的操作
- bzoj2333: [SCOI2011]棘手的操作
- bzoj2333 [SCOI2011]棘手的操作
- 【BZOJ2333】【SCOI2011】棘手的操作 treap合并
- bzoj2333: [SCOI2011]棘手的操作 线段树+离线
- [BZOJ2333][SCOI2011][可并堆]棘手的操作
- bzoj2333: [SCOI2011]棘手的操作(启发式合并做法)
- 【BZOJ2333】【SCOI2011】棘手的操作 可并堆+堆套堆(什么嘛,用个set就好啦)
- bzoj2333 棘手的操作 可并堆or dfs序列+线段树
- [BZOJ2333][SCOI2011]棘手的操作(可并堆||线段树+离线)
- [BZOJ2333][SCOI2011]棘手的操作(可并堆||线段树)
- linux命令行下如何以目录树的形式显示一个文件夹的所有文件
- vijos-p1361 2008.11.9
- android 资源种类及使用
- 数字时代的BES:从业务支撑转向商业使能
- vijos-p1323 2008.11.9
- BZOJ2333
- vijos-p1143 2008.11.9
- 探索测试(笔记)
- 打印出杨辉三角
- uva1419
- codevs 1227 方格取数2
- python-os.getcwd()
- vijos-p1139 2008.11.9
- 次优二叉树 --- 折半查找在元素不等概情况下的改进