• bzoj2333[SCOI2011]棘手的操作


    bzoj2333[SCOI2011]棘手的操作

    题意:

    有N个节点,M个操作:连接两个节点、单个节点的权值增加v、节点所在的连通块的所有节点的权值增加v、所有节点的权值增加v、询问节点当前的权值、询问节点所在的连通块中权值最大的节点的权值、询问所有节点中权值最大的节点的权值。N,M≤300000

    题解:

    可并堆,虽然听说配对堆非常快,但教程太少了不会写,所以去学了斜堆,比较好写。斜堆实际上是一棵二叉树,核心是合并操作,这是一个递归过程,有点像treap的删除操作。斜堆保证复杂度的方法是每次递归合并右节点,合并完后交换左右节点,使整棵树和splay一样,可以“自动”平衡,也是玄学。要修改整个连通块,打标记就行了。这道题特殊的一点在于询问所有节点权值的最大值,可以用STL的set维护所有连通块的根节点,当连边和修改权值时如果根节点被修改需要维护一下set。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <set>
     5 #define inc(i,j,k) for(int i=j;i<=k;i++)
     6 #define maxn 300100
     7 #define INF 0x3fffffff
     8 using namespace std;
     9 
    10 int fa[maxn],ch[maxn][2],tg[maxn],v[maxn],n,m,add;
    11 multiset <int> st;
    12 void pushdown(int x){
    13     if(tg[x]){
    14         if(ch[x][0])tg[ch[x][0]]+=tg[x],v[ch[x][0]]+=tg[x];
    15         if(ch[x][1])tg[ch[x][1]]+=tg[x],v[ch[x][1]]+=tg[x];
    16         tg[x]=0;
    17     }
    18 }
    19 int dt[maxn],dts;
    20 int find(int x){
    21     dt[dts=1]=x; while(fa[x])x=fa[x],dt[++dts]=x;
    22     for(int i=dts;i>=1;i--)pushdown(dt[i]); return x;
    23 }
    24 int merge(int x,int y){
    25     if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); pushdown(x);
    26     ch[x][1]=merge(ch[x][1],y); fa[ch[x][1]]=x; swap(ch[x][0],ch[x][1]); return x;
    27 }
    28 int del(int x){
    29     int t=merge(ch[x][0],ch[x][1]),f=fa[x]; fa[x]=ch[x][0]=ch[x][1]=0;
    30     fa[t]=f; if(f)ch[f][ch[f][1]==x]=t; return t;
    31 }
    32 void update1(int x,int val){
    33     int y=find(x); int t=del(x); v[x]+=val;
    34     if(y!=x){
    35         int z=merge(y,x); st.erase(st.find(v[y])); st.insert(v[z]);
    36     }else{
    37         if(t){
    38             int z=merge(t,x); st.erase(st.find(v[x]-val)),st.insert(v[z]);
    39         }else st.erase(st.find(v[x]-val)),st.insert(v[x]);
    40     }
    41 }
    42 void update2(int x,int val){
    43     x=find(x); tg[x]+=val; v[x]+=val; if(!fa[x])st.erase(st.find(v[x]-val)),st.insert(v[x]);
    44 }
    45 void update3(int val){add+=val;}
    46 int query1(int x){find(x); return v[x];}
    47 int query2(int x){int y=find(x); return v[y];}
    48 int query3(){return * --st.find(INF);}
    49 void connect(int x,int y){
    50     int xx=find(x),yy=find(y); if(xx==yy)return; int z=merge(xx,yy);
    51     if(z==xx)st.erase(st.find(v[yy]));else st.erase(st.find(v[xx]));
    52 }
    53 char opt[3];
    54 int main(){
    55     //freopen("test.txt","r",stdin);
    56     scanf("%d",&n); add=0; st.clear();
    57     inc(i,1,n){
    58         scanf("%d",&v[i]); st.insert(v[i]); fa[i]=ch[i][0]=ch[i][1]=tg[i]=0;
    59     }
    60     scanf("%d",&m);
    61     inc(i,1,m){
    62         scanf("%s",opt); int x,y;
    63         if(opt[0]=='U')scanf("%d%d",&x,&y),connect(x,y);
    64         if(opt[0]=='A'){
    65             if(opt[1]=='1')scanf("%d%d",&x,&y),update1(x,y);
    66             if(opt[1]=='2')scanf("%d%d",&x,&y),update2(x,y);
    67             if(opt[1]=='3')scanf("%d",&x),update3(x);
    68         }
    69         if(opt[0]=='F'){
    70             if(opt[1]=='1')scanf("%d",&x),printf("%d
    ",query1(x)+add);
    71             if(opt[1]=='2')scanf("%d",&x),printf("%d
    ",query2(x)+add);
    72             if(opt[1]=='3')printf("%d
    ",query3()+add);
    73         }
    74         //if(i==2)break;
    75     }
    76     return 0;
    77 }

    20160530

  • 相关阅读:
    吴裕雄--天生自然Numpy库学习笔记:NumPy 字节交换
    吴裕雄--天生自然Numpy库学习笔记:NumPy 排序、条件刷选函数
    吴裕雄--天生自然Numpy库学习笔记:NumPy 统计函数
    吴裕雄--天生自然Numpy库学习笔记:NumPy 算术函数
    吴裕雄--天生自然Numpy库学习笔记:NumPy 数学函数
    吴裕雄--天生自然Numpy库学习笔记:NumPy 字符串函数
    吴裕雄--天生自然Numpy库学习笔记:NumPy 位运算
    吴裕雄--天生自然Numpy库学习笔记:Numpy 数组操作
    吴裕雄--天生自然Numpy库学习笔记:NumPy 迭代数组
    CodeForces
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5658709.html
Copyright © 2020-2023  润新知