华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1179|回复: 2
打印 上一主题 下一主题

P4146 序列终结者

[复制链接]

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
跳转到指定楼层
楼主
发表于 2020-4-10 14:52:23 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
https://www.luogu.com.cn/problem/P4146

题目背景
网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……

这样我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。

这道题目就叫序列终结者吧。

题目描述
给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作:

将[L,R]这个区间内的所有数加上V。
将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。
求[L,R]这个区间中的最大值。
最开始所有元素都是0。

输入格式
第一行两个整数N,M。M为操作个数。

以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。

输出格式
对于每个第3种操作,给出正确的回答。

输入输出样例
输入 #1复制
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
输出 #1复制
2
说明/提示
N≤50000,M≤100000。

回复

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
板凳
 楼主| 发表于 2020-11-5 17:37:34 | 只看该作者
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int inf=0X3FFFFFFF;
  4. const int N=50100;
  5. struct node
  6. {
  7.         int val,fa,s[2],sz,mx,rev,add;
  8. } a[N];
  9. int n, tot, root;
  10. void ArrayPr()   /// 调试监视使用
  11. {
  12.         cout<<endl<<"  i ";
  13.         for (int i=1; i<=tot; i++) cout<<setw(3)<<i;
  14.         cout<<endl<<"val ";
  15.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].val;
  16.         cout<<endl<<" s0 ";
  17.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].s[0];
  18.         cout<<endl<<" s1 ";
  19.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].s[1];
  20.         cout<<endl<<" fa ";
  21.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].fa;
  22.         cout<<endl<<" sz ";
  23.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].sz;
  24.         cout<<endl<<" mx ";
  25.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].mx;
  26.         cout<<endl<<"add ";
  27.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].add;
  28.         cout<<endl<<"rev ";
  29.         for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].rev;
  30.         cout<<endl;
  31. }


  32. void pushdown(int rt)
  33. {
  34.         if (rt==0) return ;
  35.         int V=a[rt].add,REV=a[rt].rev;
  36.         int l=a[rt].s[0], r=a[rt].s[1];
  37.         if (V!=0)
  38.                 {
  39.                         a[rt].val+=V,a[rt].mx+=V;
  40.                         a[rt].add=0;
  41.                         if (l>0)a[l].add+=V;
  42.                         if (r>0)a[r].add+=V;
  43.                 }
  44.         if (REV>0)  /// 没写好!
  45.                 {
  46.                         a[rt].s[0]=r,a[rt].s[1]=l;
  47.                         a[rt].rev=0;
  48.                         if (l>0)a[l].rev^=1;
  49.                         if (r>0)a[r].rev^=1;
  50.                 }
  51.         ///这里感觉写的不好 没必要全传  我要保证正确



  52. }
  53. void BSTPr(int rt)   ///中序输出以rt为根的BST
  54. {
  55.         pushdown(rt);
  56.         if (rt>0)
  57.                 {
  58.                         BSTPr(a[rt].s[0]);
  59.                         cout<<a[rt].val<<' ';
  60.                         BSTPr(a[rt].s[1]);
  61.                 }
  62. }
  63. void pushup(int rt)
  64. {
  65.         int l=a[rt].s[0], r=a[rt].s[1];       
  66.         a[rt].sz=a[l].sz+a[r].sz+1;
  67.         int mxl=-inf,mxr=-inf;
  68.         if (l>0) mxl=a[l].mx+a[l].add;
  69.         if (r>0) mxr=a[r].mx+a[r].add;
  70.         a[rt].mx=max(a[rt].val,max(mxl,mxr))+a[rt].add;
  71. }
  72. int Son(int x)
  73. {
  74.         int y=a[x].fa;
  75.         return  a[y].s[1]==x;
  76. }
  77. void R(int x)
  78. {
  79.         int y=a[x].fa;
  80.         int z=a[y].fa;
  81.         pushdown(y);pushdown(x);///下传
  82.         int k=Son(x);
  83.         int v=a[x].s[k^1];///v是x另外一边的儿子将要被挂在y下面

  84.         a[y].s[k]=v,a[v].fa=y;///v挂在y下
  85.         a[z].s[Son(y)]=x,a[x].fa=z;///x挂在z下
  86.         a[x].s[k^1]=y,a[y].fa=x;///y挂在x下
  87.         pushup(y);pushup(x);///上传
  88. }
  89. inline void Splay(int x,int rt=root)  ///把x旋到rt的位置 默认rt是根
  90. {
  91.         rt=a[rt].fa;
  92.         int y,z;
  93.         ///沿途释放pushdown?

  94.         while(a[x].fa!=rt)  /// y==rt就到位
  95.                 {
  96.                         y=a[x].fa,z=a[y].fa;;
  97.                         if(z!=rt)
  98.                                 if(Son(x)==Son(y))R(y); /// 一字
  99.                                 else R(x);
  100.                         R(x);
  101.                 }
  102.         if(rt==0)root=x;
  103. }
  104. int Getkth(int rt,int k) ///第k个的数的位置
  105. {
  106.         pushdown(rt);
  107.         int l=a[a[rt].s[0]].sz;  /// RT的左儿子下的个数
  108.         if(l+1==k) return rt;
  109.         if(l+1>k) return Getkth(a[rt].s[0], k); ///左儿子里去找
  110.         if(l+1<k) return Getkth(a[rt].s[1], k-(l+1));
  111. }
  112. int Build(int l,int r)
  113. {
  114.         if (l>r) return 0;
  115.         if (l==r)
  116.                 {
  117.                         a[l].sz=1;
  118.                         return  l;
  119.                 }
  120.         int m=(l+r)/2;
  121.         int L=a[m].s[0]=Build(l,m-1);
  122.         int R=a[m].s[1]=Build(m+1,r);
  123.         a[m].sz=r-l+1;
  124.         a[L].fa=a[R].fa=m;
  125.         return m;
  126. }
  127. void Get(int x,int y) ///把 第x个转到根,y转到x的右子树
  128. {
  129.         int l=Getkth(root,x);
  130.         int r=Getkth(root,y);
  131.         Splay(l,root);
  132.         Splay(r,a[root].s[1]);
  133. }
  134. int main()
  135. {
  136.         ///freopen("4146.in","r",stdin);
  137.         ///freopen("4146.out","w",stdout);
  138.         int m,x,opt,L,R,V;
  139.         cin>>n>>m;
  140. ///初始建树
  141.         tot=n+2;
  142.         root=Build(1,tot);
  143.         a[0].val=a[1].val=a[n+2].val=-inf;///两个假节点
  144.         while(m--)
  145.                 {
  146.                         cin>>opt>>L>>R;
  147.                         Get(L,R+2);
  148.                         int t=a[root].s[1];
  149.                         t=a[t].s[0];
  150.                         ///BSTPr(root);
  151.                         if (opt==1)
  152.                                 {
  153.                                         cin>>V;
  154.                                         a[t].add+=V;
  155.                                 }
  156.                         if (opt==2)a[t].rev^=1;
  157.                         if (opt==3)
  158.                                 {
  159.                                         cout<<(a[t].mx+a[t].add)<<endl;
  160.                                 }
  161.                         if (opt==4)
  162.                                 {
  163.                                         BSTPr(root);
  164.                                         for (int i=1; i<=tot; i++) Splay(i,root);
  165.                                         BSTPr(root);
  166.                                 }
  167.                 }

  168.         return 0;
  169. }
  170. /*
  171. 10 3
  172. 1 3 8 5
  173. 2 3 9
  174. 1 3 4 1
  175. */
  176. /* 先只测试加
  177. 10 50
  178. 1 3 8 -5
  179. 1 5 9 -2
  180. 1 1 3 -1
  181. 3 3 6
  182. 4 4 4
  183. */
  184. /* 只测试转
  185. 10 17
  186. 1 1 10 1
  187. 1 2 10 1
  188. 1 3 10 1
  189. 1 4 10 1
  190. 1 5 10 1
  191. 1 6 10 1
  192. 1 7 10 1
  193. 1 8 10 1
  194. 1 9 10 1
  195. 1 10 10 1
  196. 4 4 4
  197. 2 3 8
  198. 4 4 4
  199. 2 3 6
  200. 4 4 4
  201. 2 6 9
  202. 4 4 4
  203. */
复制代码
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
沙发
 楼主| 发表于 2020-11-5 17:37:27 | 只看该作者
这个题是序列上的问题,那些数据结果可以支持薛烈上的问题呢,线段树,SPLAY,
因为涉及到翻转,这个线段树就很为难了,所对我们就用 splay,毕竟他的名字叫伸展树,可以伸展,所以处理序列比较好。

建一个SPLAY树,
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-25 13:57 , Processed in 0.468161 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表