[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;
}
原文地址:https://www.cnblogs.com/HLXZZ/p/7651226.html