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);
}
本文介绍了一道使用Splay树解决的模拟题,详细解释了如何通过Splay树实现节点的插入、删除及查找最大值操作。文章还提供了一份完整的代码示例,帮助读者理解Splay树的应用。

675

被折叠的 条评论
为什么被折叠?



