P4130,jzoj1214-[NOI2007]项链工厂【线段树】
正題
題目鏈接:https://www.luogu.org/problemnew/show/P4130
題目大意
一個(gè)環(huán)形顏色珠子鏈,位置(注意不是上面的珠子)從最上順時(shí)針下來(lái)位置依次標(biāo)號(hào)1~n1\sim n1~n。
然后要求支持以下操作
(顏色段為連續(xù)的相同顏色)
解題思路
先不考慮前兩個(gè)操作,我們可以用線段樹(shù)進(jìn)行操作。
儲(chǔ)存[l,r,w,lc,rc,lazy][l,r,w,lc,rc,lazy][l,r,w,lc,rc,lazy]分別表示下標(biāo)l~rl\sim rl~r,有www個(gè)顏色段,頭顏色為lclclc,尾顏色為rcrcrc,懶惰標(biāo)簽lazylazylazy
然后我們可以利用lc,rclc,rclc,rc進(jìn)行合并。
之后我們就可以輕易的實(shí)現(xiàn)后4個(gè)操作。
那我們考慮前兩個(gè)操作,我們會(huì)發(fā)現(xiàn)它并不會(huì)破壞連續(xù)性,也就是任何一個(gè)位置相鄰的兩個(gè)位置的數(shù)字編號(hào)也與其相鄰。
那么我們就可以使用一個(gè)十分優(yōu)秀的算法,我們用ttt記錄其旋轉(zhuǎn)了幾步,然后用BBB記錄是否翻轉(zhuǎn)(因?yàn)榉D(zhuǎn)兩次等于沒(méi)有翻轉(zhuǎn))。之后就可以計(jì)算出給出的數(shù)字段旋轉(zhuǎn)和翻轉(zhuǎn)之前應(yīng)該在哪個(gè)位置。
然后照樣計(jì)算就好了。
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);}} }總結(jié)
以上是生活随笔為你收集整理的P4130,jzoj1214-[NOI2007]项链工厂【线段树】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 3月23日是什么星座 介绍3月23日的星
- 下一篇: 欢乐纪中某A组赛【2019.7.6】