[BZOJ2333][SCOI2011]棘手的操作

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2333][SCOI2011]棘手的操作相关的知识,希望对你有一定的参考价值。

BZOJ
Luogu

sol

左偏树。
这题目真的是调死我了。
左偏树删除任意节点:把这个点的左右子树合并接在原来的父亲上,再一路往上更新一下\(dis\)即可。注意特判删除的点原先就是根的情况。
对于全局最大值,写一个可删除的双堆结构(也可以写multiset),维护每个联通块的堆顶(保证每个联通块只贡献一个),所以在修改的时候要注意删除和加入。
七个操作:
U:左偏树合并,删除一个堆中元素,注意判原本已连通的情况
A1:删除那个点,然后修改后插入
A2:暴力跳到根然后直接打标记
A3:开全局变量记录
F1:下放所有标记
F2:暴跳到根输出
F3:输出堆顶元素

code

我真的是调了两个小时

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 300005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
int n,m,fa[N],ls[N],rs[N],key[N],dis[N],tag[N],Stack[N],top,sum;
char s[10];
struct Heap{
    priority_queue<int>a,d;
    void push(int x){a.push(x);}
    void del(int x){d.push(x);}
    void clear(){while (!d.empty()&&a.top()==d.top()) a.pop(),d.pop();}
    int top(){clear();return a.top();}
}Q;
void cover(int x,int val){key[x]+=val;tag[x]+=val;}
void pushdown(int x)
{
    if (ls[x]) cover(ls[x],tag[x]);
    if (rs[x]) cover(rs[x],tag[x]);
    tag[x]=0;
}
void alldown(int x)
{
    Stack[top=1]=x;
    for (int i=x;fa[i];i=fa[i])
        Stack[++top]=fa[i];
    while (top) pushdown(Stack[top--]);
}
int getroot(int x)
{
    while (fa[x]) x=fa[x];
    return x;
}
int Merge(int x,int y)
{
    if (!x||!y) return x|y;
    if (key[x]<key[y]) swap(x,y);
    pushdown(x);pushdown(y);
    rs[x]=Merge(rs[x],y);
    fa[rs[x]]=x;
    if (dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
    dis[x]=dis[rs[x]]+1;
    return x;
}
void update(int x)
{
    while (x)
    {
        if (dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
        dis[x]=dis[rs[x]]+1;
        x=fa[x];
    }
}
void Delete(int x)
{
    alldown(x);
    fa[ls[x]]=fa[rs[x]]=0;
    if (x==ls[fa[x]]) ls[fa[x]]=0;
    else rs[fa[x]]=0;
    int y=getroot(x);
    Merge(y,Merge(ls[x],rs[x]));
    update(fa[x]);
    fa[x]=ls[x]=rs[x]=0;
}
int main()
{
    n=gi();
    for (int i=1;i<=n;i++)
        key[i]=gi(),Q.push(key[i]);
    m=gi();
    while (m--)
    {
        scanf("%s",s);
        if (s[0]=='U')
        {
            int x=gi(),y=gi();
            x=getroot(x);y=getroot(y);
            if (x==y) continue;
            int z=Merge(x,y);
            Q.del(z==x?key[y]:key[x]);
        }
        if (s[0]=='A'&&s[1]=='1')
        {
            int x=gi(),v=gi();
            int y=getroot(x);
            if (!fa[x])
            {
                Q.del(key[x]);
                pushdown(x);
                fa[ls[x]]=fa[rs[x]]=0;
                y=Merge(ls[x],rs[x]);
                fa[x]=ls[x]=rs[x]=0;
            }
            else Delete(x),Q.del(key[y]);
            key[x]+=v;
            Q.push(key[Merge(x,y)]);
        }
        if (s[0]=='A'&&s[1]=='2')
        {
            int x=gi(),v=gi();
            x=getroot(x);
            Q.del(key[x]);
            cover(x,v);
            Q.push(key[x]);
        }
        if (s[0]=='A'&&s[1]=='3') sum+=gi();
        if (s[0]=='F'&&s[1]=='1')
        {
            int x=gi();
            alldown(x);
            printf("%d\n",key[x]+sum);
        }
        if (s[0]=='F'&&s[1]=='2')
        {
            int x=gi();
            x=getroot(x);
            printf("%d\n",key[x]+sum);
        }
        if (s[0]=='F'&&s[1]=='3') printf("%d\n",Q.top()+sum);
    }
    return 0;
}

以上是关于[BZOJ2333][SCOI2011]棘手的操作的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2333 SCOI2011—棘手的操作

(右偏树)Bzoj2333: [SCOI2011]棘手的操作

bzoj千题计划218:bzoj2333: [SCOI2011]棘手的操作

bzoj千题计划217:bzoj2333: [SCOI2011]棘手的操作

[BZOJ2333][SCOI2011]棘手的操作

[bzoj2333][SCOI2011][棘手的操作]