zoukankan      html  css  js  c++  java
  • [bzoj2333] 棘手的操作

    题意:

    有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:

    U x y: 加一条边,连接第x个节点和第y个节点

    A1 x v: 将第x个节点的权值增加v

    A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v

    A3 v: 将所有节点的权值都增加v

    F1 x: 输出第x个节点当前的权值

    F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值

    F3: 输出所有节点中,权值最大的节点的权值

    题解:

    可并堆(堆套堆)

    看到这个题号,不做这个题真是对不起这个题了

    维护两个可并堆,一个是每个连通块里的可并堆,还有一个是每个连通块的堆顶所组成的堆

    由于需要修改结点,所以要用到可并堆的删除任意结点的操作,这个在hyh的论文里讲得很清楚,这个题要维护两个堆,用左偏树写起来会很蛋疼,每次要更新dis

    用斜堆写代码量会小很多......所以直接斜堆了......

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define N 300010
    using namespace std;
    
    int n,m,rt,all;
    int v[N],lazy[N],fa[N],ls[N],rs[N],fa2[N],ls2[N],rs2[N];
    char s[10];
    
    int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    int find(int x) {
      while(fa[x]) x=fa[x];
      return x;
    }
    
    int sum(int x) {
      int ret=0;
      while(fa[x]) ret+=lazy[fa[x]],x=fa[x];
      return ret;
    }
    
    void pushdown(int x) {
      if(lazy[x]) {
        v[ls[x]]+=lazy[x],v[rs[x]]+=lazy[x];
        lazy[ls[x]]+=lazy[x],lazy[rs[x]]+=lazy[x];
        lazy[x]=0;
      }
    }
    
    int merge(int x, int y) {
      if(!x || !y) return x+y;
      if(v[x]<v[y]) swap(x,y);
      pushdown(x);//2:将当前的根节点pushdown
      rs[x]=merge(rs[x],y);
      fa[rs[x]]=x;
      swap(ls[x],rs[x]);
      return x;
    }
    
    int merge2(int x, int y) {
      if(!x || !y) return x+y;
      if(v[x]<v[y]) swap(x,y);
      rs2[x]=merge2(rs2[x],y);
      fa2[rs2[x]]=x;
      swap(ls2[x],rs2[x]);
      return x;
    }
    
    int del(int x) {
      pushdown(x);
      int q=fa[x],p=merge(ls[x],rs[x]);
      fa[x]=ls[x]=rs[x]=0,fa[p]=q;
      if(!q) return p;//3:注意这里返回根的细节
      else {
        x==ls[q]?ls[q]=p:rs[q]=p;
        return find(q);
      }
    }
    
    void del2(int x) {
      int q=fa2[x],p=merge2(ls2[x],rs2[x]);
      fa2[x]=ls2[x]=rs2[x]=0,fa2[p]=q;
      if(!q) rt=p;
      else x==ls2[q]?ls2[q]=p:rs2[q]=p;
    }
    
    int main() {
      n=gi();
      for(int i=1; i<=n; i++) {
        v[i]=gi(),rt=merge2(rt,i);   
      }
      m=gi();
      while(m--) {
        scanf("%s", s);
        if(s[0]=='U') {
          int x=gi(),y=gi();
          x=find(x),y=find(y);
          if(x==y) continue;
          if(merge(x,y)==x) del2(y);
          else del2(x);
        }
        else if(s[0]=='A') {
          if(s[1]=='1') {
    	int x=gi(),w=gi(),u;
    	u=find(x),del2(u);
    	v[x]+=w+sum(x);
    	u=merge(x,del(x)),rt=merge2(rt,u);//1:合并x和删除x后的连通块
          }
          else if(s[1]=='2') {
    	int x=gi(),w=gi();
    	x=find(x),del2(x);
    	v[x]+=w,lazy[x]+=w;
    	rt=merge2(rt,x);
          }
          else all+=gi();
        }
        else {
          if(s[1]=='1') {
    	int x=gi();
    	printf("%d
    ", v[x]+sum(x)+all);
          }
          else if(s[1]=='2') {
    	int x=gi();
    	printf("%d
    ", v[find(x)]+all);
          }
          else printf("%d
    ", v[rt]+all);
        }
      }
      return 0;
    }
    
  • 相关阅读:
    至理明言100个经典句子
    ASP操作cookies的方法
    Recordset属性与方法
    VB.NET下用FSO(文件系统对象模型)实现获取硬盘信息
    诺基亚10个不为人知的秘密
    JavaScript的常用事件/方法/特效
    javascript常用方法
    C#操作xml
    URL重写
    数据库之间的区别
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7651226.html
Copyright © 2011-2022 走看看