维修数列 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 ...
随机推荐
- Lua 函数参数 & 默认实参
[1]Lua函数,默认实参 习惯了其他语言(如C++)的默认实参,利用Lua语言的过程中,发现没有默认实参这种机制. 所以,自己模拟了一个满足业务需求的带默认实参的函数. (1)示例如下: local ...
- GO函数
函数定义 Go语言中定义函数使用func关键字. func 函数名(参数)(返回值){ 函数体 } 函数名:由字母.数字.下划线组成.但函数名的第一个字母不能是数字.在同一个包内,函数名也称不能重名( ...
- post请求中body数据类型
1.application/json:json格式,如下: {"input1":"xxx","input2":"ooo" ...
- Java运行环境
Java 开发环境配置 在本章节中我们将为大家介绍如何搭建Java开发环境. Windows 上安装开发环境 Linux 上安装开发环境 安装 Eclipse 运行 Java Cloud Studio ...
- 猴子吃桃问题(Java递归实现)
猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个,第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上想再吃时,见只剩下 ...
- 字符和字符串在Java中的旅程
以下是个人对java中字符和字符串的见解,如有疏漏之处,还请不吝赐教. 下面通过一个简单的程序来说明字符和字符串在Java中的旅程. 以字符 ' 中 '为例, 它的GBK编码是2个字节:0xd6d0, ...
- 关于C#的Main(String[] args)参数输入问题
关于C#的Main(String[] args)参数输入问题 指定相关的测试代码 首先,写一个用于测试的关于Main(String[] args)参数输入有关的代码类,如下: using System ...
- main函数的的两个参数
C语言中main函数的参数有两个,这两个参数写为argc和argv.因此,main函数的函数头可写为:main(argc,argv);C语言还规定argc(第一个形参)必须是整型变量,argv( 第二 ...
- 2018年-2019年第二学期第六周C#学习个人总结
在这一周,我学习了5.4抽象类和接口.首先,抽象类当中我知道了C#允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰例如:abstract void ...
- IDEA 发布Api
1.修改Main方法 代码: public class AlicsbapiApplication extends SpringBootServletInitializer { @Override pr ...