NOI2007 项链工厂

题目背景

T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖、款式多样、价格适中,广受青年人的喜爱。

最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链。该项链自助生产系

统包括硬件系统与软件系统,软件系统与用户进行交互并控制硬件系统,硬件系统接受软件系统的命令生产指定的

项链。该系统的硬件系统已经完成,而软件系统尚未开发,T公司的人找到了正在参加全国信息学竞赛的你,你能

帮助T公司编写一个软件模拟系统吗?

题目描述

一条项链包含 N 个珠子,每个珠子的颜色是 1,2,…,c 中的一种。项链

被固定在一个平板上,平板的某个位置被标记位置 1 ,按顺时针方向其他位置被记为 2,3,…,N。

你将要编写的软件系统应支持如下命令:

输入格式

输入文件第一行包含两个整数N, c,分别表示项链包含的珠子数目以及颜色数目。

第二行包含N 个整数,x1, x2…, xn,表示从位置1 到位置N 的珠子的颜色,1 ≤ xi ≤ c。

第三行包含一个整数Q,表示命令数目。

接下来的Q 行每行一条命令,如上文所述。

输出格式

对于每一个C 和CS 命令,应输出一个整数代表相应的答案。

输入输出样例

输入 #1
5 3
1 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1
输出 #1
4
1

说明/提示

【数据规模和约定】

对于60%的数据,N ≤ 1 000,Q ≤ 1 000;

对于100%的数据,N ≤ 500 000,Q ≤ 500 000,c ≤ 1 000。

关于旋转和翻转

注意旋转命令旋转“珠子”但不改变“位置”的编号,而反转命令始终以位置 1 为对称轴。例如当 N=10 时,项链上的位置编号如图1:

但注意此时项链上的位置编号仍然如图1所示,于是翻转的对称轴不变。因而再执行一次“F”命令时,项链的颜色如图4所示。

关于CountSegment命令

CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度等于 N 时,我们仍然将查询部分作为“线段”理解。

例如在图4所示的情况中,执行“CS 1 10”命令,查询从位置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是,若执行“C”命令,返回值则为 2

 

思路:我直接服了这个题了,细节是真的很多。不过整体思路还是挺简单的,我们一步步来看,如果忽略掉rotate和flip操作,这题就是个线段树裸题,那么现在怎么办呢?考虑两个方向:1.更换新的数据结构,来处理rotate和flip,但是需要维护的数据太多,虽然也能做,但是未免过于麻烦;2.试试通过某种方法把这两个操作处理掉。我这里用的是方法2,我们维护两个变量ks和rev,表示旋转的幅度和是否翻转,通过简单的找规律和模拟,可以得出,当询问一个位置pos时,当前pos位置珠子的编号为:1.当rev==0即珠子未翻转时,编号=pos-ks;2.当rev==1即珠子翻转时,编号=ks-pos+2。不要忘记取模。于是,我们每次rotate的时候就将对应的ks加k,每次flip的时候将ks=n-ks(想想为什么),并且将rev取反。这样就能直接通过数学演算忽视掉rotate和flip的影响。

(一个细节,当询问所有珠子的时候(即C命令),如果所有珠子颜色均相同,则答案为1而非0)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 const int N = 5e5 + 5;
  8 inline int read()
  9 {
 10     int ret = 0;
 11     char c = getchar();
 12     while(c < '0' || c > '9') c = getchar();
 13     while(c >= '0' && c <= '9')
 14     {ret = ret * 10 + c - '0'; c = getchar();}
 15     return ret;
 16 }
 17 int ks = 0, rev = 0;
 18 int n, cl, m;
 19 int num[N];
 20 #define ls p << 1
 21 #define rs p << 1 | 1
 22 struct seg{
 23     int l, r;
 24     int add, lc, rc, s;
 25 }tr[N << 2];
 26 inline void update(int p)
 27 {
 28     tr[p].lc = tr[ls].lc;
 29     tr[p].rc = tr[rs].rc;
 30     tr[p].s = tr[ls].s + tr[rs].s - (tr[ls].rc == tr[rs].lc ? 1 : 0);
 31 }
 32 void build(int p, int l, int r)
 33 {
 34     tr[p].l = l;
 35     tr[p].r = r;
 36     if(l == r)
 37     {
 38         tr[p].lc = tr[p].rc = num[l];
 39         tr[p].s = 1;
 40         return;
 41     }
 42     int mid = l + r >> 1;
 43     build(ls, l, mid);
 44     build(rs, mid + 1, r);
 45     update(p);
 46 }
 47 inline void pushdown(int p)
 48 {
 49     if(tr[p].add)
 50     {
 51         int v = tr[p].add;
 52         tr[p].add = 0;
 53         tr[ls].add = v;
 54         tr[ls].lc = tr[ls].rc = v;
 55         tr[ls].s = 1;
 56         tr[rs].add = v;
 57         tr[rs].lc = tr[rs].rc = v;
 58         tr[rs].s = 1;
 59     }
 60 }
 61 void modify(int p, int l, int r, int v)
 62 {
 63     if(l <= tr[p].l && r >= tr[p].r)
 64     {
 65         tr[p].add = v;
 66         tr[p].lc = tr[p].rc = v;
 67         tr[p].s = 1;
 68         return;
 69     }
 70     pushdown(p);
 71     int mid = tr[p].l + tr[p].r >> 1;
 72     if(l <= mid) modify(ls, l, r, v);
 73     if(r > mid) modify(rs, l, r, v);
 74     update(p);
 75 }
 76 int ask_color(int p, int pos)
 77 {
 78     if(tr[p].l == tr[p].r) return tr[p].lc;
 79     int mid = tr[p].l + tr[p].r >> 1;
 80     pushdown(p);
 81     if(pos <= mid) return ask_color(ls, pos);
 82     else return ask_color(rs, pos);
 83 }
 84 inline int mo(int x)
 85 {
 86     x = (x % n + n) % n;
 87     if(!x) x = n;
 88     return x;
 89 }
 90 inline int val(int x)
 91 {
 92     if(!rev) return mo(x - ks);
 93     return mo(ks - x + 2);
 94 }
 95 seg query(int p, int l, int r)
 96 {
 97     if(l <= tr[p].l && r >= tr[p].r) return tr[p];
 98     int mid = tr[p].l + tr[p].r >> 1;
 99     seg lz = {0, 0, 0, 0, 0, 0};
100     seg rz = {0, 0, 0, 0, 0, 0};
101     seg ret;
102     pushdown(p);
103     if(l <= mid) lz = query(ls, l, r);
104     if(r > mid) rz = query(rs, l, r);
105     if(!lz.s) ret = {0, 0, 0, rz.lc, rz.rc, rz.s};
106     else if(!rz.s) ret = {0, 0, 0, lz.lc, lz.rc, lz.s};
107     else ret = {0, 0, 0, lz.lc, rz.rc, lz.s + rz.s - (lz.rc == rz.lc ? 1 : 0)};
108     return ret;
109 }
110 int main()
111 {
112     n = read(), cl = read();
113     for(int i = 1; i <= n; i ++) num[i] = read();
114     build(1, 1, n);
115     m = read();
116     char op[5];
117     int a, b, c, d, A, B;
118     seg C, D;
119     for(int i = 1; i <= m; i ++)
120     {
121         scanf("%s", op);
122         if(op[0] == 'R') a = read(), ks += a, ks %= n;
123         else if(op[0] == 'F') ks = n - ks, ks %= n, rev ^= 1;
124         else if(op[0] == 'S')
125         {
126             a = read(), b = read();
127             a = val(a), b = val(b);
128             c = ask_color(1, a), d = ask_color(1, b);
129             modify(1, a, a, d), modify(1, b, b, c);
130         }
131         else if(op[0] == 'P')
132         {
133             a = read(), b = read(), c = read();
134             a = val(a), b = val(b);
135             A = min(a, b), B = max(a, b);
136             if((((a < b) ^ rev) == 1) || (a == b)) modify(1, A, B, c);
137             else modify(1, 1, A, c), modify(1, B, n, c);
138         }
139         else if(op[0] == 'C')
140         {
141             if(op[1] == 'S')
142             {
143                 a = read(), b = read();
144                 a = val(a), b = val(b);
145                 A = min(a, b), B = max(a, b);
146                 if((((a < b) ^ rev) == 1) || (a == b)) printf("%d\n", query(1, A, B).s);
147                 else
148                 {
149                     C = query(1, 1, A), D = query(1, B, n);
150                     printf("%d\n", C.s + D.s - (C.lc == D.rc ? 1 : 0));
151                 }
152             }
153             else
154             {
155                 C = query(1, 1, n);
156                 printf("%d\n", max(1, C.s - (C.lc == C.rc ? 1 : 0)));
157             }
158         }
159     }
160     return 0;
161 }

 

posted @ 2020-03-23 22:05  Frank喵^_^  阅读(172)  评论(0编辑  收藏  举报