BZOJ2333: [SCOI2011]棘手的操作

2333: [SCOI2011]棘手的操作

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2537  Solved: 985
[Submit][Status][Discuss]

Description

N个节点,标号从1N,这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: 输出所有节点中,权值最大的节点的权值

Input

输入的第一行是一个整数N,代表节点个数。

接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。

再下一行输入一个整数Q,代表接下来的操作数。

最后输入Q行,每行的格式如题目描述所示。

Output

对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

Sample Input

3

0 0 0

8

A1 3 -20

A1 2 20

U 1 3

A2 1 10

F1 3

F2 3

A3 -10

F3

Sample Output

-10
10
10

HINT

 对于30%的数据,保证 N<=100,Q<=10000


对于80%的数据,保证 N<=100000,Q<=100000


对于100%的数据,保证 N<=300000,Q<=300000


对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

2.SCOI2011棘手的操作

完成时间:2017.7.23.21.35

时耗:3h

思路{

  题号有点小牛逼。。。。。。。。。

  看到合并,查询最大值,我们果断想到了可并堆。

  操作1:合并两个左偏树,找出两个节点所属的左偏树,合并即可

  操作2:给一特定节点的值增加v,我们可以先取出这个元素,修改它的值,合并。

  操作3:给一个左偏树的所有值增加一个数,像线段树那样打个标记都可以了。

  操作4;直接搞个全局变量记录all都可以辣。

  查询1:输出x节点的权值=当前的值加上跳父亲的lazy+全局all

  查询2:直接取堆顶元素即可。

  查询3:这个只要取各个堆的堆顶元素建一个堆,在各种操作中先删除,再单点修改,再插入。

}

 

//第一次写可并堆的数据结构火题,还是写下注释吧。。。。。。
#include<bits/stdc++.h>
#define RG register
#define il inline 
#define N 300010
using namespace std;
int l1[N],r1[N],d1[N],d2[N],v1[N],lazy[N],l2[N],r2[N],v2[N],f1[N],f2[N],rt,n,q,all;
void down(int x){
  v1[l1[x]]+=lazy[x],v1[r1[x]]+=lazy[x];
  lazy[l1[x]]+=lazy[x],lazy[r1[x]]+=lazy[x];
  lazy[x]=0;
}//下放懒标记。。
int find1(int x){int X=x;while(f1[X])X=f1[X];return X;}//找霸霸
int sum(int x){int sum=0,X=f1[x];while(X)sum+=lazy[X],X=f1[X];return sum;}//累加LAZY
int merge1(int x,int y){//大根堆
  if(!x||!y)return x+y;
  if(v1[x]<v1[y])swap(x,y);
  down(x);r1[x]=merge1(r1[x],y);f1[r1[x]]=x;
  if(d1[r1[x]]>d1[l1[x]])swap(r1[x],l1[x]);
  d1[x]=d1[r1[x]]+1;return x;
}
int merge2(int x,int y){
  if(!x||!y)return x+y;
  if(v2[x]<v2[y])swap(x,y);
  r2[x]=merge2(r2[x],y);f2[r2[x]]=x;
  if(d2[r2[x]]>d2[l2[x]])swap(r2[x],l2[x]);
  d2[x]=d2[r2[x]]+1;return x;
}
int del1(int x){down(x);
  int le=l1[x],ri=r1[x];int y=merge1(le,ri);
  if(x==l1[f1[x]])l1[f1[x]]=y;else r1[f1[x]]=y;
  f1[y]=f1[x];return find1(y);
}
void del2(int x){
  int le=l2[x],ri=r2[x];int y=merge2(le,ri);
  if(rt==x)rt=y;
  if(x==l2[f2[x]])l2[f2[x]]=y;else r2[f2[x]]=y;
  f2[y]=f2[x];
}
void getnode1(int x,int v){f1[x]=d1[x]=l1[x]=r1[x]=0,v1[x]=v;}
void getnode2(int x,int v){f2[x]=d2[x]=l2[x]=r2[x]=0,v2[x]=v;}
void U(){
  int x,y;scanf("%d%d",&x,&y);
  x=find1(x),y=find1(y);
  if(x!=y){
    if(merge1(x,y)==x)del2(y);else del2(x);
  }
}
void A1(){
  int x,v;scanf("%d%d",&x,&v);
  del2(find1(x));//堆顶元素可能不是最优的了。。。。。
  int y=del1(x);
  getnode1(x,v+v1[x]+sum(x));
  int z=merge1(y,x);getnode2(z,v1[z]);
  rt=merge2(rt,z);
}
void A2(){
  int x,v;scanf("%d%d",&x,&v);
  x=find1(x);v1[x]+=v;lazy[x]+=v;
  del2(x);getnode2(x,v1[x]);rt=merge2(rt,x);
}
void A3(){int v;scanf("%d",&v);all+=v;}
void F1(){int x;scanf("%d",&x);printf("%d\n",v1[x]+sum(x)+all);}
void F2(){int x;scanf("%d",&x);printf("%d\n",v1[find1(x)]+all);}
void F3(){printf("%d\n",v2[rt]+all);}
int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  scanf("%d",&n);
  for(int i=1;i<=n;++i)scanf("%d",&v1[i]),v2[i]=v1[i];
  scanf("%d",&q);rt=1;for(int i=2;i<=n;++i)rt=merge2(rt,i);char ch[3];
  for(int i=1;i<=q;++i){
    scanf("%s",ch);
    if(ch[0]=='U')U();
    if(ch[0]=='A'){
      if(ch[1]=='1')A1();
      if(ch[1]=='2')A2();
      if(ch[1]=='3')A3();
    }
    if(ch[0]=='F'){
      if(ch[1]=='1')F1();
      if(ch[1]=='2')F2();
      if(ch[1]=='3')F3();
    }
  }return 0;
}

 

  

 

posted @ 2017-07-23 21:46  QYP_2002  阅读(180)  评论(0编辑  收藏  举报