P3273 [SCOI2011]棘手的操作 左偏树

  一道恶心至极的左偏树题

题意:

题解:

  • 观察操作可以发现需要用两棵左偏树来维护 一棵维护全局最大值  一棵维护正常
  • 操作一:普通左偏树正常连边 全局左偏树可以删去小的那个点
  • 操作二:普通左偏树正常操作(删点-增值-merge)全局左偏树先删去x点连通块祖先 然后再加回连通块祖先  这样做比对全局左偏树也正常操作有优越性  点会越来越少  如果全局左偏树也和局部左偏树一样操作会MLE
  • 操作三:和操作二非常相似  普通左偏树的根部加一个值和懒标记即可 全局左偏树类似操作二

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int n,m,x,y,z,a[N],outdata,root;
struct zps
{
    int lson[N],rson[N],val[N],dis[N],fa[N],col[N];
    void clear(int x){lson[x]=rson[x]=fa[x]=0;}
    int getlazy(int x){int ans=0;while(x=fa[x])ans+=col[x];return ans;}
    void down(int x)
    {
        if(lson[x])val[lson[x]]+=col[x],col[lson[x]]+=col[x];
        if(rson[x])val[rson[x]]+=col[x],col[rson[x]]+=col[x];
        col[x]=0;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        if(val[x]<val[y])swap(x,y);
        down(x);
        rson[x]=merge(rson[x],y);
        fa[rson[x]]=x;
        if(dis[rson[x]]>dis[lson[x]])swap(lson[x],rson[x]);
        dis[x]=dis[rson[x]]+1;
        return x;
    }
    int getfa(int x){while(fa[x])x=fa[x];return x;}
    int delet(int x)
    {
        down(x);
        int fx=fa[x];
        int temproot=merge(lson[x],rson[x]);
        fa[temproot]=fx;
        if(fx&&lson[fx]==x)lson[fx]=temproot;
        else if(fx&&rson[fx]==x)rson[fx]=temproot;
        while(fx)
        {
            if(dis[lson[fx]]<dis[rson[fx]])swap(rson[fx],lson[fx]);
            dis[fx]=dis[rson[fx]]+1;
            temproot=fx;
            fx=fa[fx];
        }
        return temproot;
    }
    int add(int x,int v)
    {
        int fx=getfa(x);
        if(fx==x)
        {
            if(lson[x]+rson[x]==0){val[x]+=v;return x;}
            else if(lson[x])fx=lson[x];
            else if(rson[x])fx=rson[x];
        }
        delet(x);
        val[x]+=getlazy(x)+v;
        clear(x);
        return merge(getfa(fx),x);//note
    }
    int build()
    {
        queue<int>t;
        for(int i=1;i<=n;i++)t.push(i);
        int x,y,z;
        while(t.size()>1)
        {
            x=t.front();t.pop();
            y=t.front();t.pop();
            z=merge(x,y);t.push(z);
        }
        return t.front();
    }
}in,out;
char op[10];
int main()
{
    in.dis[0]=out.dis[0]=-1;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),in.val[i]=out.val[i]=a[i];
    root=out.build();
    cin>>m;
    while(m--)
    {
        scanf("%s",op+1);
        if(op[1]==‘A‘)
        {
            if(op[2]==‘1‘)
            {
                scanf("%d%d",&x,&y);
                root=out.delet(in.getfa(x));
                int temp=in.add(x,y);
                out.val[temp]=in.val[temp];
                out.clear(temp);
                root=out.merge(temp,root);
            }
            if(op[2]==‘2‘)
            {
                scanf("%d%d",&x,&y);
                int fx=in.getfa(x);
                root=out.delet(fx);
                in.val[fx]+=y;
                in.col[fx]+=y;
                out.val[fx]=in.val[fx];
                out.clear(fx);
                root=out.merge(root,fx);
            }
            if(op[2]==‘3‘)scanf("%d",&x),outdata+=x;
        }
        if(op[1]==‘F‘)
        {
            if(op[2]==‘1‘)scanf("%d",&x),printf("%d\n",in.val[x]+in.getlazy(x)+outdata);
            if(op[2]==‘2‘)scanf("%d",&x),printf("%d\n",in.val[in.getfa(x)]+outdata);
            if(op[2]==‘3‘)printf("%d\n",out.val[root]+outdata);
        }
        if(op[1]==‘U‘)
        {
            scanf("%d%d",&x,&y);
            x=in.getfa(x);y=in.getfa(y);
            if(x==y)continue;
            int temp=in.merge(x,y);
            if(temp==x)root=out.delet(y);
            else root=out.delet(x);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bxd123/p/11776236.html

时间: 2024-10-10 03:22:12

P3273 [SCOI2011]棘手的操作 左偏树的相关文章

2333: [SCOI2011]棘手的操作[离线线段树]

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Status][Discuss] Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通块的所有

bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作

2333? 先记一下吧,这题现在全部都是照着题解做的,因为怎么改都改不出来,只好对着题解改,以后还要再做过 以后再也不用指针了!太恶心了!空指针可不止直接特判那么简单啊,竟然还要因为空指针写奇怪的分类讨论! 没错,就是那个诡异的55和63行.由于要返回删除x后x所在树的新根,要分类讨论:如果x是根且其两个子节点合并后为空,那么去掉x后新树树根为空:如果x是根且其两个子节点合并后不为空,那么去掉x后新树树根为两个子节点合并后的:如果x不是根,那么去掉x后新树树根为原来的find(x). 另外,打了

【BZOJ2333】棘手的操作(左偏树,STL)

[BZOJ2333]棘手的操作(左偏树,STL) 题面 BZOJ上看把... 题解 正如这题的题号 我只能\(2333\) 神TM棘手的题目... 前面的单点/联通块操作 很显然是一个左偏树+标记 (确实很显然,只是写死人...) 然后对于全局的最大值而言 搞一个\(multi\)来水 看起来真的简单.. 写起来真的想死... 记住:要特判一下已经联通的块就不要再去\(Merge\)了 #include<iostream> #include<cstdio> #include<

关于左偏树的一些东东

大概所有的预备知识这里都有https://baike.baidu.com/item/%E5%B7%A6%E5%81%8F%E6%A0%91/2181887?fr=aladdin 例题1:洛谷 P3377 [模板]左偏树(可并堆) 383通过 1.2K提交 题目提供者HansBug 站长团 标签 难度提高+/省选- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 加了路径压缩就WA,路过dal… 左偏树用指针写会MLE吗..… m,n写反了也可以过,数据有… 哪位大神有pbds库

左偏树

概要:左偏树是具有左偏性质的堆有序二叉树,它相比于优先队列,能够实现合并堆的功能. 先仪式型orzorzozr国家集训队论文https://wenku.baidu.com/view/515f76e90975f46527d3e1d5.html 左偏树的节点定义: 1 struct node { 2 int lc, rc, val, dis; 3 } LTree[maxn]; 左偏树的几个基本性质如下: 节点的键值小于等于它的左右子节点的键值 节点的左子节点的距离不小于右子节点的距离 节点的距离等于

学习笔记——左偏树

左偏树是一个堆,为了实现快速合并的操作,我们可以构造一颗二叉树,并且使右子树尽量简短 什么是左偏呢? 定义:一个左偏树的外节点是一个左子树为空或者右子树为空的节点,对于每一个点定义一个距离dist它为到它子树内外节点的最短距离. 一个合法的左偏树节点需要满足堆性以及它的右子树的dist比左子树的dist小. 为什么要这样呢? 这样右子树的dist是严格控制在logn以内的. 于是我们合并的时候,将另一个左偏树与当前左偏树的右子树合并,这样递归下去,则时间复杂度是O(logn)的. 这就是一颗左偏

bzoj2333[SCOI2011]棘手的操作

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

poj 3016 K-Monotonic 左偏树 + 贪心 + dp

//poj 3016 K-Monotonic//分析:与2005年集训队论文黄源河提到的题目类似,给定序列a,求一序列b,b不减,且sigma(abs(ai-bi))最小.//思路:去除左偏树(大根堆)一半的节点(向上取整),让左偏树的根节点上存放中位数:每个左偏树的根节点表示一个等值区间//在本题中,我们将一段区间 与 一颗左偏树等同:将求调整给定数列 vi 为不减序列的代价 与 求取数列 bi 等同 1 #include"iostream" 2 #include"cstd

BZOJ 1455 罗马游戏 左偏树

题目大意:给定n个点,每个点有一个权值,提供两种操作: 1.将两个点所在集合合并 2.将一个点所在集合的最小的点删除并输出权值 很裸的可并堆 n<=100W 启发式合并不用想了 左偏树就是快啊~ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1001001 using namespace std; struct abcd{ abcd