维修数列 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 ...
随机推荐
- Linux Maven安装
Maven 官网,下载maven 包 http://maven.apache.org/download.cgi 下载完成:apache-maven-3.6.1-bin.tar.gz 解压到自定义目录: ...
- Tableau 学习资料
官方文档: https://www.tableau.com/zh-cn/support/help 其他教程: tablaue破解版_tableau10 破解_tableau server 破解:htt ...
- [ABP] ASP.NET Zero 5.6.0 之 ASP.NET Zero Power Tools 上手日志
之前破解了这个工具后,却没有使用它. 现在使用这个小工具,帮我完成创建Entity类,Dto类,AppService类,View视图等DDD相关工作以及Entity Framework Migrati ...
- etcd v3 备份恢复
备份数据: # ETCDCTL_API=3 etcdctl --endpoints localhost:2379 snapshot save snapshot.db 恢复数据: # ETCDCTL_A ...
- ELK学习笔记之ELK搜集OpenStack节点日志
模板来自网络,模板请不要直接复制,先放到notepad++内调整好格式,注意缩进 部署架构 控制节点作为日志服务器,存储所有 OpenStack 及其相关日志.Logstash 部署于所有节点,收集本 ...
- vue 添加旋转图片 修改css transform 值
//点击放大图片并旋转图片 conponents组建 <template> <!-- 过渡动画 --> <transition name="fade ...
- [C++ Primer Plus] 第10章、对象和类(二)课后习题
1. bank.h #include <string> using namespace std; class BankAccount { private: std::string m_na ...
- 【Alpha】Scrum Meeting 11
目录 前言 任务分配 燃尽图 会议照片 签入记录 前言 第11次会议于4月16日18:15在一公寓三楼召开. 交流确认了任务进度,讨论项目发布事宜,分配下一阶段任务.时长45min. 任务分配 姓名 ...
- 20175307《Java程序设计》第5周学习总结
教材内容总结 6.1 接口 1接口声明 接口使用关键字interface来进行声明 eg:interface 接口的名字 2接口体 接口体中包含常量的声明和抽象方法两部分(没有变量) 注意一定的要 ...
- 安全检查,Windows更新出现8024402F错误如何解决
背景,每个月都要进行例行检查,需要更新windows补丁包,病毒库等操作,谁知今天windows报错了: windows 代码8024402f 错误,原因是更新日志和缓冲出了问题. 解决步骤 : 1. ...