正题

题目链接:https://www.luogu.org/problemnew/show/P4130


题目大意

一个环形颜色珠子链,位置(注意不是上面的珠子)从最上顺时针下来位置依次标号1∼n1\sim n1∼n。

然后要求支持以下操作

  1. Rk:R\ k:R k:将所有珠子顺时针旋转kkk个。
  2. F:F:F:将所有珠子以111向下翻转
  3. Sij:S\ i\ j:S i j:交换iii和jjj上的珠子
  4. Pijk:P\ i\ j\ k:P i j k:将iii顺时针到jjj的珠子都涂上颜色kkk
  5. C:C:C:询问整个链有多少颜色段
  6. CSij:CS\ i\ j:CS i j:询问iii顺时针到jjj有多少颜色段。

(颜色段为连续的相同颜色)


解题思路

先不考虑前两个操作,我们可以用线段树进行操作。

储存[l,r,w,lc,rc,lazy][l,r,w,lc,rc,lazy][l,r,w,lc,rc,lazy]分别表示下标l∼rl\sim rl∼r,有www个颜色段,头颜色为lclclc,尾颜色为rcrcrc,懒惰标签lazylazylazy

然后我们可以利用lc,rclc,rclc,rc进行合并。

之后我们就可以轻易的实现后4个操作。

那我们考虑前两个操作,我们会发现它并不会破坏连续性,也就是任何一个位置相邻的两个位置的数字编号也与其相邻。

那么我们就可以使用一个十分优秀的算法,我们用ttt记录其旋转了几步,然后用BBB记录是否翻转(因为翻转两次等于没有翻转)。之后就可以计算出给出的数字段旋转和翻转之前应该在哪个位置。
然后照样计算就好了。


codecodecode

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=500100;
struct Tree_node{int l,r,w,lc,rc,lazy;
}ans;
int n,C,m,t,B;
struct Line_cut_tree{Tree_node t[N<<2];
//  node merge(node tl,node tr)
//  {//      node t;
//      t.w=tl.w+tr.w+(tl.rc!=tr.lc);
//      return t;
//  }void megre(Tree_node &t,Tree_node tl,Tree_node tr){t.lc=tl.lc;t.rc=tr.rc;t.w=tl.w+tr.w-(tl.rc==tr.lc);}void build(int x,int l,int r){t[x].l=l;t[x].r=r;if(l==r){scanf("%d",&t[x].lc); t[x].rc=t[x].lc;t[x].w=1;return;}int mid=(l+r)/2;build(x*2,l,mid);build(x*2+1,mid+1,r);megre(t[x],t[x*2],t[x*2+1]);}void downdata(int x){if(!t[x].lazy) return;t[x*2].lazy=t[x*2+1].lazy=t[x].lazy;t[x*2].w=t[x*2+1].w=1;t[x*2].lc=t[x*2].rc=t[x*2+1].lc=t[x*2+1].rc=t[x].lazy;t[x].lazy=0;}void Ask(int x,int l,int r){if(t[x].l==l&&t[x].r==r){if(!ans.rc) ans.lc=t[x].lc;megre(ans,ans,t[x]);return;}downdata(x);if(r<=t[x*2].r) Ask(x*2,l,r);else if(l>t[x*2].r) Ask(x*2+1,l,r);else Ask(x*2,l,t[x*2].r),Ask(x*2+1,t[x*2+1].l,r);megre(t[x],t[x*2],t[x*2+1]);}void Change(int x,int l,int r,int z){if(t[x].l==l&&t[x].r==r){t[x].w=1;t[x].lazy=t[x].rc=t[x].lc=z;return;}downdata(x);if(r<=t[x*2].r) Change(x*2,l,r,z);else if(l>t[x*2].r) Change(x*2+1,l,r,z);else Change(x*2,l,t[x*2].r,z),Change(x*2+1,t[x*2+1].l,r,z);megre(t[x],t[x*2],t[x*2+1]);}
}Tree;
void Reset()
{ans.w=ans.rc=0;}
void doing(int &x,int &y)
{if(!B){if(x>=t+1) x=x-t;else x=n-t+x;if(y>=t+1) y=y-t;else y=n-t+y;}else{if(x<=t+1) x=t-x+2;else x=t+n-x+2;if(y<=t+1) y=t-y+2;else y=t+n-y+2;swap(x,y);}
}
int main()
{scanf("%d%d",&n,&C);Tree.build(1,1,n);scanf("%d",&m);for(int i=1;i<=m;i++){char op[3];scanf("%s",op);if(op[0]=='C'){if(op[1]=='S'){int x,y;scanf("%d%d",&x,&y);if(x==y)x++,x--;doing(x,y);if(y>=x) Reset(),Tree.Ask(1,x,y);else {Tree_node a1,a2;Reset();Tree.Ask(1,x,n);a1=ans;Reset();Tree.Ask(1,1,y);a2=ans;if(B){swap(a1.lc,a1.rc);swap(a2.lc,a2.rc);swap(a1,a2);}Tree.megre(ans,a1,a2);}printf("%d\n",ans.w);}elseprintf("%d\n",max(Tree.t[1].w-(Tree.t[1].lc==Tree.t[1].rc),1));}else if(op[0]=='R'){int k;scanf("%d",&k);t=(t+k)%n;}else if(op[0]=='F') B^=1,t=n-t;else if(op[0]=='S'){int x,y;scanf("%d%d",&x,&y);doing(x,y);Reset();Tree.Ask(1,x,x);int a1=ans.lc;Reset();Tree.Ask(1,y,y);int a2=ans.lc;Tree.Change(1,x,x,a2);Tree.Change(1,y,y,a1);}else if(op[0]=='P'){int x,y,z;scanf("%d%d%d",&x,&y,&z);doing(x,y);if(y>=x) Tree.Change(1,x,y,z);else Tree.Change(1,x,n,z),Tree.Change(1,1,y,z);}}
}

P4130,jzoj1214-[NOI2007]项链工厂【线段树】相关推荐

  1. [线段树] Jzoj P1214 项链工厂

    Description T 公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱.最近T 公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中 ...

  2. 【周末狂欢赛6】[AT1219]历史研究(回滚莫队),大魔法师(矩阵+线段树),单峰排列

    文章目录 T1:单峰排列 题目 题解 code T2:历史研究 题目 题解 code T3:大魔法师 题目 题解 code 我可能这辈子都更不出来狂欢赛5了,先咕咕 T1:单峰排列 题目 一个n的全排 ...

  3. bzoj 3838: [Pa2013]Raper (线段树)

    3838: [Pa2013]Raper Time Limit: 60 Sec  Memory Limit: 128 MB Submit: 53  Solved: 27 [Submit][Status] ...

  4. BIT与线段树专项练习

    线段树专项练习 这个草稿存在于我的CSDN良久,最近一场div2的E题出现了一次线段树相关,所以开始填坑. 以下关于加法.乘法和根号线段树来自之前久远的某一天. HH的项链 第二次做,20分钟切掉.但 ...

  5. 斜率优化之李超线段树

    三对于斜率优化,分为三种类型,一是斜率单调,第二种是是斜率不单调可以二分,第三种便是毫无规律可言的斜率情况,采用李超线段树可以在log范围内快速查询与修改,且能够胜任全部情况,代码与时间复杂度都很优秀 ...

  6. 二逼平衡树——树套树(线段树套Splay平衡树)

    题面 Bzoj3196 解析 线段树和Splay两棵树套在一起,常数直逼inf,但最终侥幸过了 思路还是比较简单, 在原数组维护一个下标线段树,再在每一个线段树节点,维护一个对应区间的权值Splay. ...

  7. 线段树——HDU - 1698

    题目含义 就是初始化一堆数为1 可以经过操作把一个区间的数都改变 并求这堆数的总大小 题目分析 有一个 #include<iostream> #include<stdio.h> ...

  8. BZOJ.1558.[JSOI2009]等差数列(线段树 差分)

    BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...

  9. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

最新文章

  1. 韦东山驱动视频笔记——3.字符设备驱动程序之poll机制
  2. rds oracle utl file,本地Oracle数据上传到AWS的RDS
  3. 返回顶部小火箭(仿电脑管家)
  4. CSDN,CNBLOGS博客文章一键转载插件 终于更新了!
  5. WCF学习笔记之序列化
  6. leetcode99. 恢复二叉搜索树(优先队列)
  7. 使用openswan构建lan-to-lan ×××(KLIPS)
  8. 如何更换ppt模板内容不变_如何制作一个优秀的PPT?附18000+套精品PPT模板
  9. robocopy的退出返回代码
  10. Hive执行计划之 Group By Operator
  11. Linux 系统磁盘满处理方法
  12. 软件工程——(2)软件项目管理 思维导图
  13. MySQL8 OCP 证书
  14. visio绘图:通过excel在visio中插入表格
  15. php 跨域提交,php实现跨域提交form表单的方法
  16. Android源码下载repo以及repo init总结
  17. html5 drag api
  18. 【Zigbee】基础篇(4) Zigbee无线通信过程、无线发送温湿度信息
  19. android x86触屏驱动下载,农步祥作品 - 使用台式机和触摸屏玩Android X86 [Soomal]
  20. 计算机 管理 mmc 注册表,win10注册表编辑器没有mmc怎么办_win10恢复注册表mmc文件夹的方法-win7之家...

热门文章

  1. 今日笔记!——分析Java应用性能
  2. linux 手机 wlan信号桥,手机WLAN信号桥是什么?WLAN信号的作用和使用方法
  3. c语言 gbk字模点阵数组,GBK点阵显示字库的制作和使用
  4. 3dsmax子菜单无法选择_3DsMax—用平面图片制作3D模型
  5. python怎么读数据库的数据_python从数据库读取出来的字典怎么更加方便的插入数据库...
  6. 问题 B: 数塔问题
  7. 7-1 矩阵链相乘问题 (20 分)(思路+详解+题目解析) 动态规划做法
  8. [C++11]final关键字的使用
  9. C++ 实现带权有向图的每对顶点之间的最短路径Floyd算法(完整代码)
  10. Redis底层实现--字符串