1493: [NOI2007]项链工厂

这线段树还能不能好好用了╭(╯^╰)╮

然而Splay写起来太麻烦(虽然看起来好像很简单的样子,各种操作都支持)

于是还是滚回去用线段树,主要坑在旋转这个操作,因为线段树不能转。。。。所以只好让区间端点转一下了,所以每次操作的时候要先计算操作区间。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=500000+5;
inline int read(){
	int x=0;char ch;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
struct data{int l,r,sum;};
struct seg{
	int l,r,tag;
	data c;
}tr[N*4];
bool rev;
int n,d;
void calc(int &x,int &y){
	if(rev){
		x=(n*2+2-d-x)%n;
		y=(n*2+2-d-y)%n;
		swap(x,y);
	}else{
		x=(x+n-d)%n;
		y=(y+n-d)%n;
	}
	if(!x)x=n;if(!y)y=n;
}
inline data merge(data a,data b){
	data tmp;
	tmp.l=a.l;tmp.r=b.r;
	tmp.sum=a.sum+b.sum;
	if(a.r==b.l)tmp.sum--;
	return tmp;
}
inline void pushup(int o){
	tr[o].c=merge(tr[o<<1].c,tr[o<<1|1].c);
}
inline void pushdown(int o){
	if(tr[o].tag&&tr[o].l!=tr[o].r){
		tr[o<<1].tag=tr[o<<1|1].tag=tr[o<<1].c.l=tr[o<<1].c.r=tr[o<<1|1].c.l=tr[o<<1|1].c.r=tr[o].tag;
		tr[o<<1].c.sum=tr[o<<1|1].c.sum=1;
		tr[o].tag=0;
	}
}
void build(int o,int l,int r){
	tr[o].l=l;tr[o].r=r;
	if(l==r){
		tr[o].c.l=tr[o].c.r=read();
		tr[o].c.sum=1;
	}else{
		int m=l+r>>1;
		build(o<<1,l,m);build(o<<1|1,m+1,r);
		pushup(o);
	}
}
data query(int o,int a,int b){
	pushdown(o);
	int l=tr[o].l,r=tr[o].r;
	if(l==a&&b==r)return tr[o].c;
	else{
		int m=l+r>>1;
		if(b<=m)return query(o<<1,a,b);
		else if(m<a)return query(o<<1|1,a,b);
		else return merge(query(o<<1,a,m),query(o<<1|1,m+1,b));
	}
}
void modify(int o,int a,int b,int v){
	pushdown(o);
	int l=tr[o].l,r=tr[o].r;
	if(l==a&&b==r){
		tr[o].c.l=tr[o].c.r=tr[o].tag=v;
		tr[o].c.sum=1;
	}else{
		int m=l+r>>1;
		if(b<=m)modify(o<<1,a,b,v);
		else if(m<a)modify(o<<1|1,a,b,v);
		else{
			modify(o<<1,a,m,v);modify(o<<1|1,m+1,b,v);
		}
		pushup(o);
	}
}
int main(){
	int m;n=read();m=read();
	build(1,1,n);
	int x,y,v;
	m=read();
	char opt[10];
	while(m--){
		 scanf("%s",opt);
		 if(opt[0]=='R'){
		 	v=read();
		 	if(rev)d=(d+n-v)%n;
		 	else d=(d+v)%n;
		 }else if(opt[0]=='F')rev^=1;
		 else if(opt[0]=='S'){
		 	x=read();y=read();
		 	int a,b;data ans;
		 	calc(x,y);
		 	if(x<=y){
		 		ans=query(1,x,y);
		 		a=ans.l;b=ans.r;
		 	}else{
		 		ans=query(1,y,x);
		 		a=ans.r;b=ans.l;
		 	}
		 	modify(1,x,x,b);modify(1,y,y,a);
		 }else if(opt[0]=='P'){
		 	x=read();y=read();v=read();
		 	calc(x,y);
		 	if(x<=y)modify(1,x,y,v);
		 	else{
		 		modify(1,x,n,v);
		 		modify(1,1,y,v);
		 	}
		 }else if(opt[0]=='C'&&opt[1]=='S'){
		 	x=read();y=read();
		 	calc(x,y);
		 	if(x<=y)printf("%d\n",query(1,x,y).sum);
			else printf("%d\n",merge(query(1,x,n),query(1,1,y)).sum);
		 	
		 }else{
		 	data ans=query(1,1,n);
		 	int tmp=ans.sum;
		 	if(ans.l==ans.r)tmp=max(tmp-1,1);
		 	printf("%d\n",tmp);
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值