[线段树] Jzoj P1214 项链工厂
Description
T 公司是一家專門生產彩色珠子項鏈的公司,其生產的項鏈設計新穎、款式多樣、價格適中,廣受青年人的喜愛。最近T 公司打算推出一款項鏈自助生產系統,使用該系統顧客可以自行設計心目中的美麗項鏈。
該項鏈自助生產系統包括硬件系統與軟件系統,軟件系統與用戶進行交互并控制硬件系統,硬件系統接受軟件系統的命令生產指定的項鏈。該系統的硬件系統已經完成,而軟件系統尚未開發,T 公司的人找到了正在參加全國信息學競賽的你,你能幫助T 公司編寫一個軟件模擬系統嗎?
一條項鏈包含N 個珠子,每個珠子的顏色是1, 2, …, c 中的一種。項鏈被固定在一個平板上,平板的某個位置被標記位置1,按順時針方向其他位置被記為2,3,…,N。
你將要編寫的軟件系統應支持如下命令:
1.R k(0 < K < N) 意為Rotate k。將項鏈在平板上順時針旋轉k 個位置, 即原來處于位置1 的珠子將轉至位置k+1,處于位置2 的珠子將轉至位置k+2,依次類推。
2. F 意為Flip。將平板沿著給定的對稱軸翻轉,原來處于位置1 的珠子不動,位置2 上的珠子與位置N 上的珠子互換,位置3 上的珠子與位置N-1 上的珠子互換,依次類推。
3.S i j(1≤I,j≤N) 意為Swap i , j。將位置i 上的珠子與位置j 上的珠子互換。
4.P I j x(1≤I,j≤N,x≤c) 意為Paint i , j , x。將位置i 沿順時針方向到位置j 的一段染為顏色x。
5.C 意為Count。查詢當前的項鏈由多少個“部分”組成,我們稱項鏈中顏色相同的一段為一個“部分”。
6.CS i j(1≤I,j≤N) 意為CountSegment i , j。查詢從位置i沿順時針方向到位置j 的一段中有多少個部分組成。
Input
輸入文件第一行包含兩個整數N, c,分別表示項鏈包含的珠子數目以及顏色數目。
第二行包含N 個整數,x1, x2…, xn,表示從位置1 到位置N 的珠子的顏色,1 ≤ xi ≤ c。
第三行包含一個整數Q,表示命令數目。
接下來的Q 行每行一條命令,如上文所述。
Output
對于每一個C 和CS 命令,應輸出一個整數代表相應的答案。
Sample Input
5 31 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1
Sample Output
41
Data Constraint
Hint
【數據規模和約定】
對于60%的數據,N ≤ 1 000,Q ≤ 1 000;
對于100%的數據,N ≤ 500 000,Q ≤ 500 000,c ≤ 1 000。
?
題解
- 主要是翻轉和旋轉操作比較奇怪,其他都是線段樹基本操作
- 一個是順時針旋轉,如果不存在翻轉操作
- 我們顯然可以通過記錄順時針旋轉的次數來還原當前的一號位置
- 多了一個翻轉
- 仔細觀察,就是把順時針變為了逆時針而已
- 所以直接乘個負號,額外加一個標記就行了
代碼
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 bool rev; 6 char ch[5]; 7 int n,m,p; 8 struct data{int l,r,sum;}; 9 struct tree{int l,r,tag;data v;}t[2000005]; 10 data merge(data a,data b) 11 { 12 data r={a.l,b.r,a.sum+b.sum}; 13 if (a.r==b.l) r.sum--; 14 return r; 15 } 16 void calc(int &x,int &y) 17 { 18 if (rev) x=(n*2+2-p-x)%n,y=(n*2+2-p-y)%n,swap(x,y); 19 else x=(x-p+n)%n,y=(y-p+n)%n; 20 if (x==0) x=n; 21 if (y==0) y=n; 22 } 23 void pushdown(int d) 24 { 25 if (!t[d].tag||t[d].l==t[d].r) return; 26 int r=t[d].tag; t[d].tag=0; 27 t[d*2].tag=t[d*2+1].tag=t[d*2].v.l=t[d*2+1].v.l=t[d*2].v.r=t[d*2+1].v.r=r; 28 t[d*2].v.sum=t[d*2+1].v.sum=1; 29 } 30 void build(int d,int l,int r) 31 { 32 t[d].l=l,t[d].r=r; 33 if (l==r) 34 { 35 scanf("%d",&t[d].v.l),t[d].v.r=t[d].v.l,t[d].v.sum=1; 36 return; 37 } 38 int mid=l+r>>1; 39 build(d*2,l,mid),build(d*2+1,mid+1,r),t[d].v=merge(t[d*2].v,t[d*2+1].v); 40 } 41 data query(int d,int l,int r) 42 { 43 pushdown(d); 44 int L=t[d].l,R=t[d].r; 45 if (l==L&&r==R) return t[d].v; 46 int mid=L+R>>1; 47 if (r<=mid) return query(d*2,l,r); else if (l>mid) return query(d*2+1,l,r); else return merge(query(d*2,l,mid),query(d*2+1,mid+1,r)); 48 } 49 void modify(int d,int l,int r,int x) 50 { 51 pushdown(d); 52 int L=t[d].l,R=t[d].r; 53 if (l==L&&R==r) 54 { 55 t[d].v.l=t[d].v.r=t[d].tag=x,t[d].v.sum=1; 56 return; 57 } 58 int mid=L+R>>1; 59 if (r<=mid) modify(d*2,l,r,x); else if (l>mid) modify(d*2+1,l,r,x); else modify(d*2,l,mid,x),modify(d*2+1,mid+1,r,x); 60 t[d].v=merge(t[d*2].v,t[d*2+1].v); 61 } 62 int main() 63 { 64 freopen("data.in","r",stdin); 65 scanf("%d%d",&n,&m),build(1,1,n),scanf("%d",&m); 66 for (int x,y,z;m;m--) 67 { 68 scanf("%s",ch); 69 if (ch[0]=='R') 70 { 71 scanf("%d",&x); 72 if (rev) p=(p+n-x)%n; else p=(p+x)%n; 73 } 74 if (ch[0]=='F') rev^=1; 75 if (ch[0]=='S') 76 { 77 int a,b; data ans; 78 scanf("%d%d",&x,&y),calc(x,y); 79 if (x>y) ans=query(1,y,x),a=ans.r,b=ans.l; else ans=query(1,x,y),a=ans.l,b=ans.r; 80 modify(1,x,x,b),modify(1,y,y,a); 81 } 82 if (ch[0]=='P') 83 { 84 scanf("%d%d%d",&x,&y,&z),calc(x,y); 85 if (x<=y) modify(1,x,y,z); else modify(1,x,n,z),modify(1,1,y,z); 86 } 87 if (ch[0]=='C'&&ch[1]=='S') 88 { 89 scanf("%d%d",&x,&y),calc(x,y); data ans; 90 if (x<=y) ans=query(1,x,y); else ans=merge(query(1,x,n),query(1,1,y)); 91 printf("%d\n",ans.sum); 92 } 93 if (ch[0]=='C'&&ch[1]!='S') 94 { 95 data ans=query(1,1,n); 96 int r=ans.sum; 97 if (ans.l==ans.r) r=max(r-1,1); 98 printf("%d\n",r); 99 } 100 } 101 }?
轉載于:https://www.cnblogs.com/Comfortable/p/11142764.html
總結
以上是生活随笔為你收集整理的[线段树] Jzoj P1214 项链工厂的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法题系列
- 下一篇: oracle建库及plsql建表空间的用