维修数列 Splay(这可能是我写过最麻烦的题之一了。。。用平衡树维护dp。。。丧心病狂啊。。。。)
题目来源BZOJ1500
这题的思路:
1、这题的话,稍微会splay的人,一般前面四个都不是问题。。主要是最后的一个,要你在修改的同时要维护好最大字段和。。。
2、最大字段和其实就是区间合并。具体操作可以看POJ2750,这是这道题的简化版本。
3、然后这题就是三个区间合并嘛。。。慢慢讨论就好了。。。这题写了我一天的时间。。从吃完午饭一直写到了晚上8点才AC。。。
直接贴代码吧。。这题是我为了学LCT,所以想做做Splay的题先熟悉一下Splay。。。结果选了这个BOSS题。。。心理阴影。。。。
我觉得我pushup那段写的挺清楚的23333 思路可以看我的pushup和pushdown函数的代码,应该挺好懂的
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack> using namespace std; const int N=,INF=0x3f3f3f3f; struct Splay_Tree
{
struct Node
{
int val,sum,cover,Size,son[],mxl,mxr,mx;
bool rev,cov;
void init(int _val)
{
val=sum=mxl=mxr=mx=_val;
Size=;
rev=cov=cover=son[]=son[]=;
}
} T[N];
stack<int>mem;
int fa[N],root,tot; void pushDown(int x)///下放标记(序列操作)
{
if(x==)return ;
if(T[x].cov)
{
if(T[x].son[])
{
T[T[x].son[]].cov=;
T[T[x].son[]].cover=T[T[x].son[]].val=T[x].cover;
T[T[x].son[]].sum=T[x].cover*T[T[x].son[]].Size;
T[T[x].son[]].rev=;
if(T[x].cover>=)
T[T[x].son[]].mx=T[T[x].son[]].mxl=T[T[x].son[]].mxr=T[x].cover*T[T[x].son[]].Size;
else
T[T[x].son[]].mx=T[T[x].son[]].mxl=T[T[x].son[]].mxr=T[x].cover;
}
if(T[x].son[])
{
T[T[x].son[]].cov=;
T[T[x].son[]].cover=T[T[x].son[]].val=T[x].cover;
T[T[x].son[]].sum=T[x].cover*T[T[x].son[]].Size;
T[T[x].son[]].rev=;
if(T[x].cover>=)
T[T[x].son[]].mx=T[T[x].son[]].mxl=T[T[x].son[]].mxr=T[x].cover*T[T[x].son[]].Size;
else
T[T[x].son[]].mx=T[T[x].son[]].mxl=T[T[x].son[]].mxr=T[x].cover;
}
T[x].cov=T[x].cover=T[x].rev=;
}
if(T[x].rev)
{
if(T[x].son[])
{
T[T[x].son[]].rev^=;
swap(T[T[x].son[]].mxl,T[T[x].son[]].mxr);
}
if(T[x].son[])
{
T[T[x].son[]].rev^=;
swap(T[T[x].son[]].mxl,T[T[x].son[]].mxr);
}
swap(T[x].son[],T[x].son[]);
T[x].rev=;
}
} void pushUp(int x)///更新节点(序列操作)
{
T[x].Size=;
T[x].sum=T[x].val;
if(T[x].son[])
T[x].sum+=T[T[x].son[]].sum,T[x].Size+=T[T[x].son[]].Size;
if(T[x].son[])
T[x].sum+=T[T[x].son[]].sum,T[x].Size+=T[T[x].son[]].Size; if(T[x].son[]&&T[x].son[])
{
T[x].mx=T[x].val;
T[x].mx=max(T[x].mx,T[T[x].son[]].mx);
T[x].mx=max(T[x].mx,T[T[x].son[]].mx);
T[x].mx=max(T[x].mx,T[T[x].son[]].mxr+T[x].val+T[T[x].son[]].mxl);
T[x].mx=max(T[x].mx,T[x].val+T[T[x].son[]].mxr);
T[x].mx=max(T[x].mx,T[x].val+T[T[x].son[]].mxl); T[x].mxl=T[T[x].son[]].mxl;
T[x].mxl=max(T[x].mxl,T[T[x].son[]].sum+T[x].val);
T[x].mxl=max(T[x].mxl,T[T[x].son[]].sum+T[x].val+T[T[x].son[]].mxl); T[x].mxr=T[T[x].son[]].mxr;
T[x].mxr=max(T[x].mxr,T[T[x].son[]].sum+T[x].val);
T[x].mxr=max(T[x].mxr,T[T[x].son[]].sum+T[x].val+T[T[x].son[]].mxr);
}
else if(T[x].son[]&&!T[x].son[])
{
T[x].mx=max(T[T[x].son[]].mxr+T[x].val,T[T[x].son[]].mx); T[x].mx=max(T[x].mx,T[x].val); T[x].mxl=max(T[T[x].son[]].mxl,T[T[x].son[]].sum+T[x].val); T[x].mxr=max(T[x].val,T[x].val+T[T[x].son[]].mxr);
}
else if(!T[x].son[]&&T[x].son[])
{
T[x].mx=max(T[T[x].son[]].mxl+T[x].val,T[T[x].son[]].mx); T[x].mx=max(T[x].mx,T[x].val); T[x].mxl=max(T[x].val,T[x].val+T[T[x].son[]].mxl); T[x].mxr=max(T[T[x].son[]].mxr,T[T[x].son[]].sum+T[x].val);
}
else T[x].mxl=T[x].mxr=T[x].mx=T[x].val; } /*inline void up(int x)///更新节点(普通平衡树操作)
{
T[x].Size=1;
if(T[x].son[0])
T[x].Size+=T[T[x].son[0]].Size;
if(T[x].son[1])
T[x].Size+=T[T[x].son[1]].Size;
}*/ void Rotate(int x,int kind)///旋转,有左旋右旋(反正配合splay用就好了233)
{
int y=fa[x],z=fa[y];
T[y].son[!kind]=T[x].son[kind],fa[T[x].son[kind]]=y;
T[x].son[kind]=y,fa[y]=x;
T[z].son[T[z].son[]==y]=x,fa[x]=z;
pushUp(y);
} void Splay(int x,int goal)///把下标为x的元素旋转到目标的儿子节点
{
if(x==goal)return ;
while(fa[x]!=goal)
{
int y=fa[x],z=fa[y];
pushDown(z),pushDown(y),pushDown(x);
int rx=T[y].son[]==x,ry=T[z].son[]==y;
if(z==goal)Rotate(x,rx);
else
{
if(rx==ry)Rotate(y,ry);
else Rotate(x,rx);
Rotate(x,ry);
}
}
pushUp(x);
if(goal==)root=x;
} int Select(int pos)///查找第k小元素
{
pos--;
int u=root;
pushDown(u);
while(T[T[u].son[]].Size!=pos)
{
if(pos<T[T[u].son[]].Size)u=T[u].son[];
else
{
pos-=T[T[u].son[]].Size+;
u=T[u].son[];
}
pushDown(u);
}
return u;
} void Reverse(int L,int R)///序列操作的区间翻转
{
if(L>R)return ;
int u=Select(L-),v=Select(R+);
Splay(u,);
Splay(v,u);
T[T[v].son[]].rev^=;
swap(T[T[v].son[]].mxl,T[T[v].son[]].mxr);
pushDown(T[v].son[]);
update(T[v].son[]);
} void Cover(int L,int R,int Val)///序列操作的区间翻转
{
if(L>R)return ;
int u=Select(L-),v=Select(R+);
Splay(u,);
Splay(v,u);
T[T[v].son[]].cov=;
T[T[v].son[]].cover=T[T[v].son[]].val=Val;
pushDown(T[v].son[]);
update(T[v].son[]);
} int build(int L,int R,int *a)///区间操作建树
{
if(L>R)return ;
int mid=(L+R)>>,sL,sR;
int loc=mem.top();mem.pop();
T[loc].init(a[mid]);
if(L==R)return loc;
T[loc].son[]=sL=build(L,mid-,a);
T[loc].son[]=sR=build(mid+,R,a);
fa[sL]=fa[sR]=loc;
pushUp(loc);
return loc;
} void init(int n,int *a)///区间操作,输入n个元素建树
{
T[].init(INF);
for(int i=;i>=;i--)
mem.push(i);
root=build(,n,a),fa[root]=;
fa[]=,T[].son[]=root,T[].Size=;
} void Insert(int pos,int n,int *a)
{
if(n==)return ;
int u=Select(pos-),v=Select(pos);
Splay(u,);
Splay(v,u);
fa[T[v].son[]=build(,n,a)]=v;
update(T[v].son[]);
} void Delete(int L,int R)
{
if(L>R)return ;
int u=Select(L-),v=Select(R+);
Splay(u,);
Splay(v,u);
Free(T[v].son[]);
T[v].son[]=;
update(v);
} int Get_sum(int L,int R)
{
if(L>R)return ;
int u=Select(L-),v=Select(R+);
Splay(u,);
Splay(v,u);
if(T[v].son[])
return T[T[v].son[]].sum;
else return ;
} int Get_max(int L,int R)
{
if(L>R)return ;
int u=Select(L-),v=Select(R+);
Splay(u,);
Splay(v,u);
if(T[v].son[])
return T[T[v].son[]].mx;
else return ;
} void Free(int x)
{
if(x==)return ;
Free(T[x].son[]);
mem.push(x);
Free(T[x].son[]);
} /*void Insert(int &t,int val,int par=0)///普通平衡树,往某个地方的下面插入元素,一般是插入根节点
{
if(t==0)
{
t=++tot;
T[t].init(val);
fa[t]=par;
Splay(tot,0);
}
else
{
int cur=t;
if(val<T[t].val)Insert(T[t].son[0],val,cur);
//else if(val==T[t].val)return ;
else Insert(T[t].son[1],val,cur);
up(cur);
}
}*/ /*int find(int t,int v)///普通平衡树查找值为v的元素
{
if(t==0)return 0;
else if(T[t].val==v)
{
Splay(t,0);
return t;
}
else if(v<T[t].val)return find(T[t].son[0],v);
else return find(T[t].son[1],v);
}*/ ///删除根节点元素
/*void Delete()
{
if(!T[root].son[0])
{
fa[T[root].son[1]]=0;
root=T[root].son[1];
}
else
{
int cur=T[root].son[0];
while(T[cur].son[1])cur=T[cur].son[1];
Splay(cur,root);
T[cur].son[1]=T[root].son[1];
root=cur,fa[cur]=0,fa[T[root].son[1]]=root;
up(root);
}
}*/ int size()
{
return T[root].Size;
} ///从t开始找值为v的前驱,返回值
int pred(int t,int v)
{
if(t==)return v;
else
{
if(v<=T[t].val)return pred(T[t].son[],v);
else
{
int ans=pred(T[t].son[],v);
if(ans==v)
ans=T[t].val,Splay(t,);
return ans;
}
}
}
///查找下标t节点的前驱返回下标
int pred(int t)
{
Splay(t,);
int u=T[t].son[];
if(u==)return fa[t];
while(T[u].son[])u=T[u].son[];
return u;
} ///从t开始找值为v的后继,返回值
int succ(int t,int v)
{
if(t==)return v;
else
{
if(v>=T[t].val)return succ(T[t].son[],v);
else
{
int ans=succ(T[t].son[],v);
if(ans==v)
ans=T[t].val,Splay(t,);
return ans;
}
}
} ///查找下标t节点的后继返回下标
int succ(int t)
{
Splay(t,);
int u=T[t].son[];
if(u==)return fa[t];
while(T[u].son[])u=T[u].son[];
return u;
} void Preorder( int t ){///输出成序列顺便检查是否有逻辑错误
if( !t ) return;
pushDown(t);
Preorder( T[t].son[] );
if(T[t].son[]&&fa[T[t].son[]]!=t)
printf("!");
printf("%d " , T[t].val );
Preorder( T[t].son[] );
} /*void init()///普通平衡树初始化
{
T[0].init(-INF);
tot=root=0;
}*/ void update(int x)///更新下标为x的节点。。手动操作后调用
{
while(x!=)
pushUp(x),x=fa[x];
} }; Splay_Tree tree; int a[N]; char str[]; int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n+;i++)
scanf("%d",a+i);
tree.init(n+,a);
int sum=n;
while(m--)
{
scanf("%s",str+);
if(str[]=='S')
{
int pos,tot;
scanf("%d%d",&pos,&tot);
pos++;
pos++;
sum+=tot;
for(int i=;i<=tot;i++)
scanf("%d",a+i);
tree.Insert(pos,tot,a);
}
else if(str[]=='L')
{
int pos,tot;
scanf("%d%d",&pos,&tot);
pos++;
tree.Delete(pos,pos+tot-);
sum-=tot;
}
else if(str[]=='K')
{
int pos,tot,cov;
scanf("%d%d%d",&pos,&tot,&cov);
pos++;
tree.Cover(pos,pos+tot-,cov);
}
else if(str[]=='V')
{
int pos,tot;
scanf("%d%d",&pos,&tot);
pos++;
tree.Reverse(pos,pos+tot-);
}
else if(str[]=='T')
{
int pos,tot;
scanf("%d%d",&pos,&tot);
pos++;
printf("%d\n",tree.Get_sum(pos,pos+tot-));
}
if(str[]=='X')
{
printf("%d\n",tree.Get_max(,tree.size()-));
}
}
return ;
}
维修数列 Splay(这可能是我写过最麻烦的题之一了。。。用平衡树维护dp。。。丧心病狂啊。。。。)的更多相关文章
- 【BZOJ-1500】维修数列 Splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 11047 Solved: 3460[Submit][Statu ...
- [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...
- bzoj 1500: [NOI2005]维修数列 splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 6556 Solved: 1963[Submit][Status ...
- BZOJ 1500: [NOI2005]维修数列 (splay tree)
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 4229 Solved: 1283[Submit][Status ...
- 【BZOJ1500】[NOI2005]维修数列 Splay
[BZOJ1500][NOI2005]维修数列 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行 ...
- BZOJ1500: [NOI2005]维修数列[splay ***]
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12278 Solved: 3880[Submit][Statu ...
- BZOJ1500: [NOI2005]维修数列 [splay序列操作]【学习笔记】
以前写过这道题了,但我把以前的内容删掉了,因为现在感觉没法看 重写! 题意: 维护一个数列,支持插入一段数,删除一段数,修改一段数,翻转一段数,查询区间和,区间最大子序列 splay序列操作裸题 需要 ...
- BZOJ1500 [NOI2005]维修数列(Splay tree)
[Submit][Status][Discuss] Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Inp ...
- bzoj1500: [NOI2005]维修数列 (Splay+变态题)
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 11353 Solved: 3553 [Submit][Status][Discuss] Descrip ...
随机推荐
- highcharts 大数据 String+,StringBuilder,String.format运行效率比较
实现String字符串相加的方法有很多,常见的有直接相加,StringBuilder.append和String.format,这三者的运行效率是有差异的,String是final类型的,每次相加都会 ...
- CentOS-7.3 设置静态 ip
1. VMnet8 必须设置固定 ip,否则会发生:虚拟机可以访问主机和外网,但是主机 windows 却访问不了虚拟机 2. 虚拟网络编辑器设置网关 IP(G): 必须与 VMnet8 的 ip 在 ...
- Java-对象及变量的并发访问小结
1)多线程环境下,方法内的变量是线程安全的 2)多个线程同时处理一个实例,这个实例内的变量是不安全的 3)不同线程中注入同一个类的不同实例,实例中的变量是安全的 4)Synchronized获取到的锁 ...
- MIUI系统如何获取ROOT权限
MIUI系统有么好方法启用了Root超级权限?各位都清楚,Android手机有Root超级权限,一旦手机启用了root相关权限,就能够实现更多的功能,举例子,各位公司的营销部门的同事,使用大多数营销工 ...
- jdk版本相关问题
1.switch在jdk1.7版本之后开始支持String类型: 2.maven3版本默认支持jdk版本为jdk1.5 3.编辑器中jdk版本设置为1.7或1.8版本,但未指定maven中的jdk版本 ...
- Git_GitHub-使用过程遇到的问题——坑(持续添加)
push错误——>master git push -u origin master 最后找到解决办法如下: 1.先删除远程 Git 仓库 $ git remote rm origin 2.再添加 ...
- zentao安装升级
------------------------一键安装8.4.1版本-------------------------------------1.查看操作系统版本[root@kvm-180 soft ...
- windows微信双开
下面的代码写到xxx.bat文件中 @echo off start /d "D:\software\WeChat\" WeChat.exe start /d "D:\so ...
- ORACLE数据库找回用户密码
安装完oracle数据库后,登录时sys,system,scott这几个用户密码输入后都不对,查阅资料后解决 1,cmd下输入sqlplus,之后让你输入用户名,输入这个 "/as sysd ...
- 王之泰/王志成《面向对象程序设计(java)》第十一周学习总结
第一部分:理论知识学习部分 第十一章理论知识主要为集合类的介绍,在实验中都有所体现且本周主要复习回顾上周的泛型程序设计 第二部分:实验部分 ——集合 1.实验目的与要求 (1) 掌握Vetor.Sta ...