节点数据TYVJ P1742 - [NOI2005]维护序列
上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助。今天在这里和大家一起学习一下节点数据
SOL:用了这么强大的数据结构。。。看到这句话就学习了“三鲜徒弟评论说splay-tree功能更强大,并且有很多其他数据结构无法实现的功能”。这功能各种强大,应用函数比较多。慢慢理解吧~看完这个忽然对线段树如梦初醒啊。
# include<cstdio>
# include<algorithm>
using std::swap;
using std::max;
# define LL long long
# define inf 1<<29
# define keytree (chd[chd[root][1]][0])
# define N 500005
int fa[N],chd[N][2],val[N],sz[N];
int root,tot1,tot2;
int q[N],s[N]; //回收内存
int num[N];
int sam[N],sum[N],lx[N],rx[N],mx[N];
bool rev[N];
/*
* Splay Tree
* 所处理的数组下标为1-N,为实现方便,在0和N+1的位置增长一个key为keyInf的结点
* select()函数中的kth与实际下边的关系如下
* keyInf - num - num - num - num - keyInf
* 0 1 2 3 4 5
* 另外用0节点替换空节点
*
* 注意1.每次插入,修改,翻转等操纵后须要旋转keytree到根节点,以维护相关值 splay(keytree,0).删除操纵特外,PushUp停止更新
* 注意2.初始化节点0的相关值必须根据题意调整,如mx,lx,rx...
* 注意3.PushDown操纵时,只要该节点打上标记了,就必须更新该节点的相关值,懒散标记只是起到标记作用(可查看rev操纵)
*/
/*
* 更新关键字
*/
void PushUp(int x)
{
int lson=chd[x][0],rson=chd[x][1];
sz[x]=sz[lson]+1+sz[rson];
sum[x]=sum[lson]+val[x]+sum[rson];
mx[x]=max(mx[lson],mx[rson]);
mx[x]=max(mx[x],max(0,rx[lson])+val[x]+max(0,lx[rson]));
lx[x]=max(lx[lson],sum[lson]+val[x]+max(0,lx[rson]));
rx[x]=max(rx[rson],sum[rson]+val[x]+max(0,rx[lson]));
}
void update_rev(int x)
{
if(x)
{
rev[x]^=1;
swap(chd[x][0],chd[x][1]);
swap(lx[x],rx[x]);
}
}
void update_sam(int x,int c)
{
if(x)
{
sam[x]=1;
val[x]=c;
sum[x]=sz[x]*c;
mx[x]=lx[x]=rx[x]=max(c,sz[x]*c);
}
}
/*
* 标记下放
*/
void PushDown(int x)
{
if(rev[x])
{
update_rev(chd[x][0]);
update_rev(chd[x][1]);
rev[x]=0;
}
if(sam[x])
{
update_sam(chd[x][0],val[x]);
update_sam(chd[x][1],val[x]);
sam[x]=0;
}
}
/*
* 旋转操纵, t=0 表现左旋, t=1 表现右旋
*/
void rotate(int x,int t)
{
int y=fa[x];
PushDown(y);
PushDown(x);
chd[y][!t]=chd[x][t];
fa[chd[x][t]]=y;
fa[x]=fa[y];
if(fa[x])
chd[fa[y]][chd[fa[y]][1]==y]=x;
chd[x][t]=y;
fa[y]=x;
PushUp(y);
}
/*
* 旋转使x成为goal的子节点,若goal为0则x旋转为根节点
*/
void splay(int x,int goal)
{
PushDown(x);
while(fa[x]!=goal)
{
if(fa[fa[x]]==goal)
rotate(x,chd[fa[x]][0]==x);
else
{
int y=fa[x],z=fa[y];
int t=(chd[z][0]==y);
if(chd[y][t]==x)
rotate(x,!t),rotate(x,t);
else
rotate(y,t),rotate(x,t);
}
}
PushUp(x);
if(goal==0)
root=x;
}
/*
* 找到位置为k的节点,返回其值,并将其升至x的儿子
*/
int select(int k,int goal)
{
int x=root;
PushDown(x);
while(sz[chd[x][0]]!=k)
{
if(k<sz[chd[x][0]])
x=chd[x][0];
else
{
k-=(sz[chd[x][0]]+1);
x=chd[x][1];
}
PushDown(x);
}
int kth=val[x];
splay(x,goal);
return kth;
}
/*
* 将以x为根的整棵子树删除掉,并回收内存
*/
void erase(int x)
{
int f=fa[x],head=0,tail=0;
for(q[tail++]=x;head<tail;head++)
{
s[tot2++]=q[head];
if(chd[q[head]][0])
q[tail++]=chd[q[head]][0];
if(chd[q[head]][1])
q[tail++]=chd[q[head]][1];
}
chd[f][chd[f][1]==x]=0;
PushUp(f);
}
/*
* 在x节点处生成一个新的节点,值为x,父节点为f,之前删除的节点会放到s中以便再利用
*/
void newnode(int &x,int v,int f)
{
if(tot2)
x=s[--tot2];
else
x=++tot1;
chd[x][0]=chd[x][1]=0;
sum[x]=mx[x]=val[x]=v;
lx[x]=rx[x]=max(0,v);
sam[x]=rev[x]=0;
fa[x]=f;
sz[x]=1;
}
/*
* 用num数组中[l,r]区间内的值建立
*/
void build(int &x,int l,int r,int f)
{
if(l<=r)
{
int m=(l+r)>>1;
newnode(x,num[m],f);
build(chd[x][0],l,m-1,x);
build(chd[x][1],m+1,r,x);
PushUp(x);
}
}
/*
* 停止初始化工作,根据题意调整0节点的相关值,其他不须要挑战呢个
*/
void init()
{
chd[0][0]=chd[0][1]=fa[0]=sz[0]=0;
root=tot1=tot2=0;
sum[0]=rev[0]=0;
mx[0]=lx[0]=rx[0]=-inf;
newnode(root,-1,0);
newnode(chd[root][1],-1,root);
sz[root]=2;
}
/*
* 1.在pos后插入tot个数据(tot个数据存于num数组中)
*/
void Insert(int pos,int tot)
{
select(pos,0);
select(pos+1,root);
build(keytree,1,tot,chd[root][1]);
splay(keytree,0);
}
/*
* 2.删除从pos开始的tot个数据
*/
void Delete(int pos,int tot) //2.删除
{
select(pos-1,0);
select(pos+tot,root);
erase(keytree);
PushUp(chd[root][1]);
PushUp(root);
}
/*
* 3.从pos开始的tot个数据都转变成c
*/
void MakeSame(int pos,int tot,int c)
{
select(pos-1,0);
select(pos+tot,root);
update_sam(keytree,c);
splay(keytree,0);
}
/*
* 4.从pos开始的tot个数据停止翻转
*/
void Reverse(int pos,int tot)
{
select(pos-1,0);
select(pos+tot,root);
update_rev(keytree);
splay(keytree,0);
}
/*
* 5.获得从pos开始的tot个数据和
*/
void GetSum(int pos,int tot) //5.求和
{
select(pos-1,0);
select(pos+tot,root);
printf("%d\n",sum[keytree]);
}
/*
* 6.最大自序列和
*/
void MaxSum()
{
select(0,0);
select(sz[root]-1,root);
printf("%d\n",mx[keytree]);
}
int main()
{
int i,j,n,m,pos,tot,l,r,c;
char op[20];
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
build(keytree,1,n,chd[root][1]);
splay(keytree,0);
for(i=1;i<=m;i++)
{
scanf("%s",op);
if(op[2]=='S')
{
scanf("%d%d",&pos,&tot);
for(j=1;j<=tot;j++)
scanf("%d",&num[j]);
Insert(pos,tot);
}
else if(op[2]=='L')
{
scanf("%d%d",&pos,&tot);
Delete(pos,tot);
}
else if(op[2]=='K')
{
scanf("%d%d%d",&pos,&tot,&c);
MakeSame(pos,tot,c);
}
else if(op[2]=='V')
{
scanf("%d%d",&pos,&tot);
Reverse(pos,tot);
}
else if(op[2]=='T')
{
scanf("%d%d",&pos,&tot);
GetSum(pos,tot);
}
else
MaxSum();
}
}
return 0;
}
文章结束给大家分享下程序员的一些笑话语录:
一位程序员去海边游泳,由于水性不佳,游不回岸了,于是他挥着手臂,大声求.救:“F1,F1!”
---------------------------------
原创文章 By
节点和数据
---------------------------------

浙公网安备 33010602011771号