【BZOJ2151】种树,贪心+Splay乱搞

原创 2016年08月29日 20:55:42

Time:2016.08.29
Author:xiaoyimi
转载注明出处谢谢


传送门
模拟题之一
我真不知道怎么证明的
考试的时候纯粹是胡思乱想啊啊啊
具体做法就是把这n个数摆成一个环,记录每个数i左边和右边(前驱和后继)记作L[i],R[i]
每次取出一个最大的数data[x]记到答案中,把x重新赋值为data[x]-data[L[x]]-data[R[x]],删去x的前驱和后继L[x],R[x],然后更新x的前驱和后继
当时YY,感觉和最大权闭合子图有些类似
什么残流思想……不是很懂
完整的证明: orz大神
这样的话我们需要一个能够维护插入,删除,求最大值的数据结构
是什么呢?
GTMD堆
太弱只会Splay,不喜欢手打堆,因为在noip2015上手写堆给我留下了阴影……
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M 200003
using namespace std;
int n,m,root;
int L[M],R[M];
struct Splay{
    int fa,ch[2],siz,data;
}a[M]; 
void ct(int x){a[x].siz=a[a[x].ch[0]].siz+a[a[x].ch[1]].siz+1;}
void made(int id,int x){a[id].data=x;a[id].siz=1;a[id].fa=0;a[id].ch[0]=a[id].ch[1]=0;}
void rorate(int x,bool mk)
{
    int y=a[x].fa;
    a[y].ch[!mk]=a[x].ch[mk];
    a[a[x].ch[mk]].fa=y;
    if (a[y].fa)
    {
        if (a[a[y].fa].ch[0]==y) a[a[y].fa].ch[0]=x;
        else a[a[y].fa].ch[1]=x;
    }
    a[x].fa=a[y].fa;
    a[y].fa=x;
    a[x].ch[mk]=y;
    ct(y);ct(x);
}
void splay(int x,int goal)
{
    int y;
    while (a[x].fa!=goal)
    {
        y=a[x].fa;
        if (a[y].fa==goal)
        {
            if(a[y].ch[0]==x) rorate(x,1);
            else rorate(x,0);
        }
        else if (a[a[y].fa].ch[0]==y)
        {
            if (a[y].ch[0]==x) rorate(y,1);
            else rorate(x,0);
            rorate(x,1);
        }
        else
        {
            if (a[y].ch[1]==x) rorate(y,0);
            else rorate(x,1);
            rorate(x,0);
        }
    }
    if(!goal) root=x;
}
void insert(int id,int x)
{
    made(id,x);
    if (!root) {root=id;return;}
    int now=root,f=1;
    while (f)
    {
        a[now].siz++;
        if (a[now].data<=x)
            if (a[now].ch[1]) now=a[now].ch[1];
            else f=0,a[now].ch[1]=id,a[id].fa=now;
        else
            if (a[now].ch[0]) now=a[now].ch[0];
            else f=0,a[now].ch[0]=id,a[id].fa=now;
    }
    splay(id,0);
}
int find_max(int now)
{
    while (a[now].ch[1]) now=a[now].ch[1];
    return now;
}
void del(int id)
{
    splay(id,0);
    if (a[id].siz==1) root=0;
    else if (!a[id].ch[0])
        root=a[id].ch[1],
        a[root].fa=0;
    else if (!a[id].ch[1])
        root=a[id].ch[0],
        a[root].fa=0;
    else
        splay(find_max(a[root].ch[0]),root),
        a[a[root].ch[1]].fa=a[root].ch[0],
        a[a[root].ch[0]].ch[1]=a[root].ch[1],
        a[a[root].ch[0]].fa=0,
        root=a[root].ch[0];
        ct(root);
}
main()
{
    scanf("%d%d",&n,&m);
    int x;
    if (m>(n/2)) {printf("Error!\n");return 0;}
    for (int i=1;i<=n;++i)
        scanf("%d",&x),
        insert(i,x);
    for (int i=1;i<=n;i++)
        L[i]=i-1,R[i]=i+1;
    L[1]=n;R[n]=1;
    int ans=0;
    for (;m;--m)
    {
        x=find_max(root);
        ans+=a[x].data;
        del(x);
        insert(x,a[L[x]].data+a[R[x]].data-a[x].data);
        del(L[x]);del(R[x]);
        int ll=L[x],rr=R[x];
        R[L[ll]]=x;L[x]=L[ll];
        L[R[rr]]=x;R[x]=R[rr];
    }
    printf("%d\n",ans);
}

版权声明:不转不是中国人!(滑稽)

spfa||贪心——洛谷P1250 种树

https://www.luogu.org/problem/show?pid=1250 贪心这个很简单吧; 就是按右端排序; 当前区间不满则在右端种树; 这样可以保证重复最多; spfa就很...
  • largecub233
  • largecub233
  • 2017年06月02日 08:21
  • 208

bzoj2151[国家集训队2011] 种树

贪心+优先队列
  • u010336344
  • u010336344
  • 2017年03月11日 17:27
  • 200

bzoj 2151 种树(贪心+堆)(经典)

思路: 看到题,第一反应就是搜索,学了一年,还太水。。看了大神的博客。如下: 分析: 首先考虑如果没有“相邻位置不能都种”这一限制会怎么样。这时就是一个裸的贪心——按照A[i]从大到小排序,然后...
  • kaisa158
  • kaisa158
  • 2015年07月20日 14:47
  • 1077

【国家集训队2011】【BZOJ2151】种树

Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观...
  • CreationAugust
  • CreationAugust
  • 2015年01月02日 17:42
  • 917

【bzoj2151】【种树】【堆+贪心】

DescriptionA城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度A...
  • sunshinezff
  • sunshinezff
  • 2015年08月30日 19:51
  • 1396

[BZOJ2151]种树(贪心+堆)

在所有别人能给你造成的伤害中,破坏性最强、后果持续最久的一种,是让你怀疑自己配不上拥有任何好的事物。...
  • Clove_unique
  • Clove_unique
  • 2016年08月28日 17:03
  • 622

[bzoj2151]种树

[国家集训队2011]种树 【问题描述】 A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且...
  • FZHvampire
  • FZHvampire
  • 2015年02月09日 09:53
  • 1182

BZOJ2151 种树

额,好久不刷BZ了,这个月一直在做TC和CF-_- 这题,每次选当前最大的,然后把这个,这个左边和这个右边都删了,在这个位置加进来一个新数,值等于左边加右边减自己 用链表+set维护即可 跟生日...
  • neither_nor
  • neither_nor
  • 2016年10月27日 12:57
  • 356

BZOJ2151 种树 贪心+双向链表+优先队列

#include #define LL long long #define clr(x,i) memset(x,i,sizeof(x)) #define mp make_pair #define pi...
  • Wolf_Reiser
  • Wolf_Reiser
  • 2017年12月05日 20:59
  • 47

[BZOJ2151]种树

同1150 每次取最大,然后把val[l]+val[r]-val[now]放入堆中 /*******************************************************...
  • u013233739
  • u013233739
  • 2015年02月10日 16:42
  • 341
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【BZOJ2151】种树,贪心+Splay乱搞
举报原因:
原因补充:

(最多只允许输入30个字)