bzoj2333[SCOI2011]棘手的操作

可以大力写一个平衡树启发式合并,除了每个连通块维护一个平衡树再对全局维护一个平衡树,每个节点表示某一个连通块的最大值.我的常数比较大,危险地卡过去了.

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=300005;
struct node{
  node *ch[2];int Max,mark,ord,num,key,sz;
  node(int x,int w){
    ord=rand();num=x;Max=key=w;mark=0;
    ch[0]=ch[1]=0;sz=1;
  }
  void update(){
    Max=key;sz=1;
    if(ch[0])sz+=ch[0]->sz;
    if(ch[1])sz+=ch[1]->sz;
    if(ch[0]&&ch[0]->Max>Max)Max=ch[0]->Max;
    if(ch[1]&&ch[1]->Max>Max)Max=ch[1]->Max;
  }
  void add(int x){
    Max+=x;mark+=x;key+=x;
  }
  void pushdown(){
    if(mark){
      if(ch[0])ch[0]->add(mark);
      if(ch[1])ch[1]->add(mark);
      mark=0;
    }
  }
};
node* Super;
void rot(node* &rt,int t){
  node* c=rt->ch[t];rt->pushdown();c->pushdown();
  rt->ch[t]=c->ch[t^1];c->ch[t^1]=rt;rt=c;
  c->ch[t^1]->update();c->update();
}
void Insert(node* &rt,int x,int w){//printf("%d %d\n",x,w);
  if(!rt){
    rt=new node(x,w);return;
  }
  int t=(x>rt->num);
  rt->pushdown();
  Insert(rt->ch[t],x,w);
  rt->update();
  if(rt->ch[t]->ord>rt->ord)rot(rt,t);
}
void remove(node* &rt,int x){
  if(rt->num!=x){
    rt->pushdown();
    remove(rt->ch[x>rt->num],x);rt->update();
  }else{
    if(!rt->ch[0]){
      rt=rt->ch[1];
    }else if(!rt->ch[1]){
      rt=rt->ch[0];
    }else if(rt->ch[0]->ord>rt->ch[1]->ord){
      rot(rt,0);remove(rt->ch[1],x);rt->update();
    }else{
      rot(rt,1);remove(rt->ch[0],x);rt->update();
    }
  }
}
int ufs[maxn];
int find(int x){
  return (x==ufs[x])?x:ufs[x]=find(ufs[x]);
}
node* root[maxn];
void Union(node* rt1,node* &rt2){
  if(!rt1)return;
  Insert(rt2,rt1->num,rt1->key);rt1->pushdown();
  Union(rt1->ch[0],rt2);Union(rt1->ch[1],rt2);
  delete rt1;
}
void link(int a,int b){
  int ra=find(a),rb=find(b);
  if(root[ra]->sz>root[rb]->sz)swap(ra,rb);
  ufs[ra]=rb;
  Union(root[ra],root[rb]);
  remove(Super,ra);remove(Super,rb);Insert(Super,find(a),root[find(a)]->Max);
}
void incr(node* rt,int x,int w){
  rt->pushdown();
  if(x==rt->num){
    rt->key+=w;rt->update();return;
  }else{
    incr(rt->ch[x>rt->num],x,w);rt->update();return;
  }
}
int getkey(node* rt,int x){
  rt->pushdown();
  if(rt->num==x)return rt->key;
  return getkey(rt->ch[x>rt->num],x);
}
int Globalmark=0;
int main(){
  int n;scanf("%d",&n);
  int x;
  for(int i=1;i<=n;++i){
    scanf("%d",&x);
    Insert(Super,i,x);
    root[i]=new node(i,x);
    ufs[i]=i;
  }
  char buf[5];
  int m;scanf("%d",&m);
  int a,b;
  for(int i=1;i<=m;++i){
    scanf("%s",buf);
    if(buf[0]=='U'){
      scanf("%d%d",&a,&b);
      if(find(a)!=find(b))link(a,b);
    }
    else if(buf[0]=='A'){
      if(buf[1]=='1'){
    scanf("%d%d",&a,&b);
    incr(root[find(a)],a,b);remove(Super,find(a));Insert(Super,find(a),root[find(a)]->Max);
      }else if(buf[1]=='2'){
    scanf("%d%d",&a,&b);
    root[find(a)]->add(b);incr(Super,find(a),b);
      }else{
    scanf("%d",&b);Globalmark+=b;
      }
    }else if(buf[0]=='F'){
      if(buf[1]=='1'){
    scanf("%d",&a);printf("%d\n",getkey(root[find(a)],a)+Globalmark);
      }else if(buf[1]=='2'){
    scanf("%d",&a);printf("%d\n",root[find(a)]->Max+Globalmark);
      }else{
    printf("%d\n",Super->Max+Globalmark);
      }
    }
  }
  return 0;
}

 

posted @ 2017-02-14 11:29  liu_runda  阅读(292)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难