zoukankan      html  css  js  c++  java
  • bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333

    稍微复杂,参考了博客:http://hzwer.com/5780.html

    用 set 维护全局的最大值就可以方便地删除和查询了;

    大概就是写一堆关于可并堆的子函数吧;

    这里还用了斜堆,但其实并不明白原因是什么...

    斜堆和左偏树只有一点点不同,它不用 dis ,而是每次都交换左右儿子,随机地保证了复杂度?

    要注意 solvetag 函数是要把跟 x 有关的所有 lzy 关系都处理掉,所以也要处理 x 到其儿子的;

    还有 del 处的顺序,小心不要让 set 查询的东西为空。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    using namespace std;
    int const maxn=3e5+5;
    int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top;
    multiset<int>st;
    char ch[5];
    int find(int x){while(fa[x])x=fa[x]; return x;}
    void pushdown(int x)
    {
        if(!lzy[x])return;
        if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x];
        if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x];
        lzy[x]=0;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        if(a[x]<a[y])swap(x,y);
        pushdown(x);
        rs[x]=merge(rs[x],y);
        fa[rs[x]]=x;
        swap(ls[x],rs[x]);
        return x;
    }
    void solvetag(int x)
    {
    //    x=fa[x];    //从 x 开始,使 x 对儿子没有 lzy 的关联 
        while(x)sta[++top]=x,x=fa[x];
        while(top)pushdown(sta[top]),top--;
    }
    int del(int x)
    {
        solvetag(x);
        int f=fa[x],k=merge(ls[x],rs[x]);
        ls[x]=rs[x]=fa[x]=0;
        fa[k]=f;
        if(ls[f]==x)ls[f]=k;
        else rs[f]=k;
        return find(k);
    }
    int rd()
    {
        int ret=0,f=1; char cc=getchar();
        while(cc<'0'||cc>'9'){if(cc=='-')f=-1; cc=getchar();}
        while(cc>='0'&&cc<='9')ret=(ret<<3)+(ret<<1)+cc-'0',cc=getchar();
        return ret*f;
    }
    int main()
    {
        n=rd();
        for(int i=1;i<=n;i++)a[i]=rd(),st.insert(a[i]);
        m=rd();
        for(int i=1,x,y;i<=m;i++)
        {
            cin>>ch;
            if(ch[0]=='U')
            {
                x=rd(); y=rd();
                x=find(x); y=find(y);
                if(x==y)continue;//
                if(merge(x,y)==x)st.erase(st.find(a[y]));
                else st.erase(st.find(a[x]));
            }
            if(ch[0]=='A'&&ch[1]=='1')
            {
                x=rd(); y=rd();
                solvetag(x);
    //            int u=del(x); a[x]+=y;
    //            st.erase(st.find(a[u])); //如果 x 只有自己,则删除后为空! 则RE 
    //            st.insert(a[merge(u,x)]);
                st.erase(st.find(a[find(x)]));
                a[x]+=y;
                st.insert(a[merge(x,del(x))]);
            }
            if(ch[0]=='A'&&ch[1]=='2')
            {
                x=rd(); y=rd();
                int u=find(x); lzy[u]+=y; a[u]+=y;
                st.erase(st.find(a[u]-y));
                st.insert(a[u]);
            }
            if(ch[0]=='A'&&ch[1]=='3')y=rd(),ad+=y;
            if(ch[0]=='F'&&ch[1]=='1')x=rd(),solvetag(x),printf("%d
    ",a[x]+ad);
            if(ch[0]=='F'&&ch[1]=='2')x=rd(),printf("%d
    ",a[find(x)]+ad);
            if(ch[0]=='F'&&ch[1]=='3')printf("%d
    ",*(--st.end())+ad);
        }
        return 0;
    }

    但是左偏树也可以做,而且也许是 set 常数太大,两种做法用时相差无几(都很慢,5000ms+);

    不过比斜堆多开了一个数组呢。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    using namespace std;
    int const maxn=3e5+5;
    int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top,dis[maxn];
    multiset<int>st;
    char ch[5];
    int find(int x){while(fa[x])x=fa[x]; return x;}
    void pushdown(int x)
    {
        if(!lzy[x])return;
        if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x];
        if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x];
        lzy[x]=0;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        if(a[x]<a[y])swap(x,y);
        pushdown(x);
        rs[x]=merge(rs[x],y);
        fa[rs[x]]=x;
        if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]);
        if(rs[x])dis[x]=dis[rs[x]]+1;
        else dis[x]=0;
        return x;
    }
    void solvetag(int x)
    {
    //    x=fa[x];    //从 x 开始,使 x 对儿子没有 lzy 的关联 
        while(x)sta[++top]=x,x=fa[x];
        while(top)pushdown(sta[top]),top--;
    }
    int del(int x)
    {
        solvetag(x);
        int f=fa[x],k=merge(ls[x],rs[x]);
        ls[x]=rs[x]=fa[x]=dis[x]=0;
        fa[k]=f;
        if(ls[f]==x)ls[f]=k;
        else rs[f]=k;
        return find(k);
    }
    int rd()
    {
        int ret=0,f=1; char cc=getchar();
        while(cc<'0'||cc>'9'){if(cc=='-')f=-1; cc=getchar();}
        while(cc>='0'&&cc<='9')ret=(ret<<3)+(ret<<1)+cc-'0',cc=getchar();
        return ret*f;
    }
    int main()
    {
        n=rd();
        for(int i=1;i<=n;i++)a[i]=rd(),st.insert(a[i]);
        m=rd();
        for(int i=1,x,y;i<=m;i++)
        {
            cin>>ch;
            if(ch[0]=='U')
            {
                x=rd(); y=rd();
                x=find(x); y=find(y);
                if(x==y)continue;//
                if(merge(x,y)==x)st.erase(st.find(a[y]));
                else st.erase(st.find(a[x]));
            }
            if(ch[0]=='A'&&ch[1]=='1')
            {
                x=rd(); y=rd();
                solvetag(x);
    //            int u=del(x); a[x]+=y;
    //            st.erase(st.find(a[u])); //如果 x 只有自己,则删除后为空! 则RE 
    //            st.insert(a[merge(u,x)]);
                st.erase(st.find(a[find(x)]));
                a[x]+=y;
                st.insert(a[merge(x,del(x))]);
            }
            if(ch[0]=='A'&&ch[1]=='2')
            {
                x=rd(); y=rd();
                int u=find(x); lzy[u]+=y; a[u]+=y;
                st.erase(st.find(a[u]-y));
                st.insert(a[u]);
            }
            if(ch[0]=='A'&&ch[1]=='3')y=rd(),ad+=y;
            if(ch[0]=='F'&&ch[1]=='1')x=rd(),solvetag(x),printf("%d
    ",a[x]+ad);
            if(ch[0]=='F'&&ch[1]=='2')x=rd(),printf("%d
    ",a[find(x)]+ad);
            if(ch[0]=='F'&&ch[1]=='3')printf("%d
    ",*(--st.end())+ad);
        }
        return 0;
    }
  • 相关阅读:
    笔记-归并排序
    Repeated Substring Pattern
    Assign Cookies
    Number of Boomerangs
    Paint Fence
    Path Sum III
    Valid Word Square
    Sum of Two Integers
    Find All Numbers Disappeared in an Array
    First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/Zinn/p/9600297.html
Copyright © 2011-2022 走看看