【SCOI2011 Day2】棘手的操作

问题描述

有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: 输出所有节点中,权值最大的节点的权值

输入格式

  输入的第一行是一个整数N,代表节点个数。
  接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。
  再下一行输入一个整数Q,代表接下来的操作数。
  最后输入Q行,每行的格式如题目描述所示。

输出格式

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

样例输入

3
0 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3

样例输出

-10
10
10

数据范围

对于30%的数据,保证 N<=100,Q<=10000
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000


题解

我们来维护一个斜堆。
合并操作和A3就不说了。
先来搞A2。在堆顶放一个Lzay标记即可。但为了保证下放标记,每次在GetFather时都要将该点到堆顶的所有点下放标记(具体见代码中的gf()函数)。
再搞A1我们先删后加。找到这个点的堆顶(过程中下放标记),在合并它(修改的点)的左右儿子,再把它的左右儿子接它的父亲。再修改该点,将该点与堆顶合并。
F1、F2不说,注意下放标记就行。
F3。。。本蒟蒻不会用set和multset,于是用一种叫“垃圾堆”的神奇方法。将每一次修改前的点投入Trash优先队列中,修改后的点投入Query优先队列中。面对询问,只要两个队列的最大元素相同,就删除它们(因为它已经不存在了)。是不是很玄妙?
综上,这真是棘手的操作。太棘手了。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
priority_queue<int> qu,tr;
const int Q=666666;
int ls[Q],rs[Q],v[Q],f[Q],lazy[Q],n;
void pd(int x)
{
    if((!lazy[x])||(!x))return;
    if(ls[x])v[ls[x]]+=lazy[x],lazy[ls[x]]+=lazy[x];
    if(rs[x])v[rs[x]]+=lazy[x],lazy[rs[x]]+=lazy[x];
    lazy[x]=0;
}
int merge(int x,int y)
{
    if((!x)||(!y))return x|y;
    pd(x),pd(y);
    if(v[x]<v[y])swap(x,y);
    rs[x]=merge(rs[x],y);
    f[rs[x]]=x;
    swap(ls[x],rs[x]);
    return x;
}
stack<int> st;
int gf(int x)
{
    int WDWDF=x;
    st.push(x);
    while(f[x]){
        x=f[x];
        WDWDF=x;
        st.push(x);
    }
    while(st.size())pd(st.top()),st.pop();
    return WDWDF;
}
int del(int x)
{
    int lls=ls[x],rrs=rs[x],y,fa=f[x],ha;
    ha=gf(x);
    y=merge(lls,rrs);
    ls[x]=rs[x]=f[x]=0;
    if(ls[fa]==x)ls[fa]=y;
    else rs[fa]=y;
    f[y]=fa;
    return gf(y);
}
int main()
{
    char o;
    int i,x,y,m,fx,fy,all=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&v[i]),f[i]=0,qu.push(v[i]);
    for(scanf("%d",&m);m;--m)
        while(true)
        {
            o=getchar();
            if(o=='A')
            {
                scanf("%d",&i);
                if(i==3){
                    scanf("%d",&x);
                    all+=x;
                }else
                if(i==1){
                    scanf("%d%d",&x,&y);
                    int a=gf(x);
                    tr.push(v[a]);
                    v[x]+=y;
                        qu.push(v[merge(del(x),x)]);

                }else
                if(i==2){
                    scanf("%d%d",&x,&y);
                    x=gf(x);
                    tr.push(v[x]);
                    v[x]+=y;
                    lazy[x]+=y;
                    qu.push(v[x]);
                }
                break;
            }
            if(o=='F')
            {
                scanf("%d",&i);
                if(i==3){
                    while(qu.size()&&tr.size()&&qu.top()==tr.top())
                    qu.pop(),tr.pop();
                    printf("%d\n",qu.top()+all);
                }else
                if(i==2){
                    scanf("%d",&x);
                    printf("%d\n",v[gf(x)]+all);
                }else{
                    scanf("%d",&x);
                    gf(x);
                    printf("%d\n",v[x]+all);
                }
                break;
            }
            if(o=='U')
            {
                scanf("%d%d",&x,&y);
                x=gf(x),y=gf(y);
                if(x!=y){
                    tr.push(v[x]),tr.push(v[y]);
                    qu.push(v[merge(x,y)]);
                }
                break;
            }
        }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/includelhc/article/details/79769126