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

http://www.lydsy.com/JudgeOnline/problem.php?id=2333

上次那个是线段树,再发一个左偏树

维护两种左偏树

第一种是对每个联通块维护一个左偏树

第二种是对所有第一种左偏树的根节点维护一个左偏树

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 300001

/*void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==‘-‘) f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
    x*=f;
}*/

struct Leftist
{
    int fa[N],lc[N],rc[N];
    int dis[N];
    int val[N],tag[N];

    int st[N];

    void addsingle(int x,int y)
    {
        if(!x) return;
        val[x]+=y;
        tag[x]+=y;
    }

    void down(int x)
    {
        if(!tag[x]) return;
        addsingle(lc[x],tag[x]);
        addsingle(rc[x],tag[x]);
        tag[x]=0;
    }

    void download(int x)
    {
        int top=0;
        for(int i=x;i;i=fa[i]) st[++top]=i;
        for(;top;--top) down(top);
    }

    int merge(int x,int y)
    {
        if(!x || !y) return x+y;
        if(val[x]<val[y]) swap(x,y);
        down(x);
        rc[x]=merge(rc[x],y);
        if(dis[lc[x]]<dis[rc[x]]) swap(lc[x],rc[x]);
        if(!rc[x]) dis[x]=0;
        else dis[x]=dis[rc[x]]+1;
        if(lc[x]) fa[lc[x]]=x;
        if(rc[x]) fa[rc[x]]=x;
        return x;
    }

    void del(int &root,int x)
    {
        int y=fa[x];
        bool k= rc[y]==x;
        x=merge(lc[x],rc[x]);
        fa[x]=y;
        if(!y) { root=x; return; }
        if(k) rc[y]=x;
        else lc[y]=x;
        if(dis[lc[y]]<dis[rc[y]]) swap(lc[y],rc[y]);
        x=rc[y];
        while(y && dis[y]!=dis[x]+1)
        {
            dis[y]=dis[x]+1;
            y=fa[y];
            if(dis[lc[y]]<dis[rc[y]]) swap(lc[y],rc[y]);
            x=rc[y];
        }
    }

    void push(int id,int &root,int x)
    {
        fa[id]=lc[id]=rc[id]=dis[id]=tag[id]=0;
        val[id]=x;
        root=merge(root,id);
    }

}q,Q;

int F[N];

int find(int i)
{
    return F[i]==i ? i : F[i]=find(F[i]);
}

int main()
{
    int n,m,x,y;
    char s[4];
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&x);
        q.push(i,F[i],x);
        Q.push(i,F[0],x);
    }
    scanf("%d",&m);
    int add=0;
    while(m--)
    {
        scanf("%s",s);
        if(s[0]==‘U‘)
        {
            scanf("%d",&x);
            scanf("%d",&y);
            x=find(x);  y=find(y);
            if(x==y) continue;
            Q.del(F[0],x);
            Q.del(F[0],y);
            F[x]=F[y]=q.merge(x,y);
            x=F[x];
            Q.push(x,F[0],q.val[x]);
        }
        else if(s[0]==‘A‘)
        {
            if(s[1]==‘1‘)
            {
                 scanf("%d",&x);
                 scanf("%d",&y);
                 find(x);
                 Q.del(F[0],F[x]);
                 q.download(x);
                 int tmp=q.val[x];
                 q.del(F[x],x);
                 int z=F[x];
                 if(z)
                 {
                     F[z]=z;
                     q.push(x,F[z],tmp+y);
                     F[x]=F[z];
                 }
                 else q.push(x,F[x],tmp+y);
                 Q.push(F[x],F[0],q.val[F[x]]);
            }
            else if(s[1]==‘2‘)
            {
                scanf("%d",&x);
                scanf("%d",&y);
                x=find(x);
                Q.del(F[0],x);
                q.addsingle(x,y);
                Q.push(x,F[0],q.val[x]);
            }
            else
            {
                scanf("%d",&x);
                add+=x;
            }
        }
        else
        {
            if(s[1]==‘1‘)
            {
                scanf("%d",&x);
                q.download(x);
                printf("%d\n",q.val[x]+add);
            }
            else if(s[1]==‘2‘)
            {
                scanf("%d",&x);
                x=find(x);
                printf("%d\n",q.val[x]+add);
            }
            else printf("%d\n",Q.val[F[0]]+add);
        }
    }
}

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8391122.html

时间: 2024-10-02 03:54:32

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

bzoj千题计划242:bzoj4034: [HAOI2015]树上操作

http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<iostream> using namespace std; #define N 100001 typedef long long LL; int n,a[N]; int front[N],nxt[N<<1],to[N<<1],tot; int fa[N],siz[N],dep[N]

bzoj2333[SCOI2011]棘手的操作

bzoj2333[SCOI2011]棘手的操作 题意: 有N个节点,M个操作:连接两个节点.单个节点的权值增加v.节点所在的连通块的所有节点的权值增加v.所有节点的权值增加v.询问节点当前的权值.询问节点所在的连通块中权值最大的节点的权值.询问所有节点中权值最大的节点的权值.N,M≤300000 题解: 可并堆,虽然听说配对堆非常快,但教程太少了不会写,所以去学了斜堆,比较好写.斜堆实际上是一棵二叉树,核心是合并操作,这是一个递归过程,有点像treap的删除操作.斜堆保证复杂度的方法是每次递归合

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

http://www.lydsy.com/JudgeOnline/problem.php?id=2333 读入所有数据,先模拟一遍所有的合并操作 我们不关心联通块长什么样,只关心联通块内有谁 所以可以把一个联通块用一个链表存储 合并x和y时,y的链表整体接到x的链表后面 这样就成了线性结构 按照链表顺序重新给序列标号即可用线段树维护 一遍过,^_^ #include<cstdio> #include<iostream> #include<algorithm> using

bzoj千题计划111:bzoj1021: [SHOI2008]Debt 循环的债务

http://www.lydsy.com/JudgeOnline/problem.php?id=1021 如果A收到了B的1张10元,那么A绝对不会把这张10元再给C 因为这样不如B直接给C优 由此可以推出 若A欠B20元,B欠C 30元, 那么A还C20元,B还C10元最优 所以一共只有 A->BC   B->AC  C->AB AB->C  BC->A  AC->B 这6种转移情况 根据输入,我们可以知道三人最终手中有多少钱ea.eb.ec,一共有多少钱sum 设f

bzoj千题计划185:bzoj1260: [CQOI2007]涂色paint

http://www.lydsy.com/JudgeOnline/problem.php?id=1260 区间DP模型 dp[l][r] 表示涂完区间[l,r]所需的最少次数 从小到大们枚举区间[l,r] 如果col[l]==col[r] dp[l][r]=min(dp[l+1][r],dp[l][r-1],dp[l+1][r-1]+1) 否则 dp[l][r]=min(dp[l][k]+dp[k+1][r]) 我还是辣鸡啊~~~~(>_<)~~~~,这种题都不能秒 #include<c

bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹

http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len [i] 表示以i结尾的最长不下降子序列的长度 pre_sum[i] 表示对应长度下的方案数 suf_len[i] 表示以i开头的最长不下降子序列长度 suf_sum[i] 表示对应长度下的方案数 若已有了这4个数组 设最长上升子序列长度=mx 那么 如果pre_len[i]+suf_len[i] -

bzoj千题计划304:bzoj3676: [Apio2014]回文串

https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300001 char ss[N]; int s[N]; int tot=1,last; int fail[N],len

bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include<cstdio> #include<cstring> #include<iostream> #define L 100001 typedef unsigned long long ULL; using namespace std; char s[L+4]; int tot,root

bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic

http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 用b数组表示 节点第0/1行的最右一列是否连接了右边 来 辅助 节点的合并 查询 对两个点位于矩形的位置分4种情况讨论 两点是否联通,要考虑四种情况 (以两个位置是矩形左上角和右上角为例) 1.直接联通,线段树的节点包含了这种情况,直接判断 2. 3. 4. 后三种情况需要再查询[1,l]和[r,n