[jzoj 1214] [luogu 4130] [NOI2007]项链工厂 {线段树}

题目

https://www.luogu.org/problemnew/show/P4130


解题思路

S p l a y 不 会 \color{red}Splay不会 Splay,那就正经的打线段树。
这道题目的后4问,就是纯正的线段树。
对于前两问,其实只是改变了每一个端点的位置,但没有改变他们的顺序,所以我们可以记录下他们的翻转次数和旋转次数,查询时倒推回去就可以了。
细节很多。

比如打函数名的时候,注意 s w a p swap swap是常用库中的定义函数,尽量不要重复。


代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std; 
const int N=500010; 
int n,m,flag,Q,sum,b[N]; char ch[5]; 
struct node{
	int l,r,lv,rv,cn,la; 
}a[N*4];
inline int read(){
	int p=0; char c=getchar(); 
	while (!isdigit(c)) c=getchar(); 
	while (isdigit(c)) p=p*10+c-48,c=getchar(); 
	return p; 
}
void up(int x){
	a[x].cn=a[x*2].cn+a[x*2+1].cn; 
	if (a[x*2].rv==a[x*2+1].lv) a[x].cn--; 
	a[x].lv=a[x*2].lv,a[x].rv=a[x*2+1].rv; 
}
void pushlazy(int x){
	if (a[x].la){
		a[x*2].lv=a[x*2].rv=a[x*2].la=a[x].la; 
		a[x*2+1].lv=a[x*2+1].rv=a[x*2+1].la=a[x].la; 
		a[x*2].cn=a[x*2+1].cn=1; 
		a[x].la=0; 
	}
}
void build(int x){
	if (a[x].l==a[x].r){
		a[x].lv=a[x].rv=b[a[x].l]; a[x].cn=1; return; 
	}
	int mid=(a[x].l+a[x].r)>>1; 
	a[x*2].l=a[x].l,a[x*2].r=mid;
	a[x*2+1].l=mid+1,a[x*2+1].r=a[x].r; 
	build(x*2),build(x*2+1); up(x); 
}
int find(int x,int k){
	if (a[x].l==a[x].r) return a[x].lv; 
	pushlazy(x); 
	int mid=(a[x].l+a[x].r)>>1; 
	if (k<=mid) find(x*2,k); else find(x*2+1,k); 
}
void change(int x,int k,int val){
	if (a[x].l==k&&a[x].r==k){
		a[x].lv=a[x].rv=val; a[x].cn=1; return; 
	}
	pushlazy(x); 
	int mid=(a[x].l+a[x].r)>>1; 
	if (k<=mid) change(x*2,k,val); else change(x*2+1,k,val); 
	up(x); 
}
void changes(int x,int l,int r,int val){
	if (a[x].l==l&&a[x].r==r) {
		a[x].lv=a[x].rv=a[x].la=val; a[x].cn=1; return; 
	}
	if (a[x].l==a[x].r) return; 
	pushlazy(x); 
	int mid=(a[x].l+a[x].r)>>1; 
	if (r<=mid) changes(x*2,l,r,val); 
	else if (l>mid) changes(x*2+1,l,r,val); 
	else changes(x*2,l,mid,val),changes(x*2+1,mid+1,r,val); 
	up(x); 
}
void Swap(int x,int y){
	int qx=find(1,x),qy=find(1,y); 
	change(1,y,qx),change(1,x,qy);
}
int ask(int x,int l,int r){
	if (a[x].l==l&&a[x].r==r) return a[x].cn; 
	pushlazy(x); 
	int mid=(a[x].l+a[x].r)>>1; 
	if (r<=mid) return ask(x*2,l,r); 
	if (l>mid) return ask(x*2+1,l,r); 
	int ans=ask(x*2,l,mid)+ask(x*2+1,mid+1,r); 
	if (a[x*2].rv==a[x*2+1].lv) ans--; 
	return ans; 
}
int get(){
	int x=read();
	if (flag) x=n-x+2; 
	return ((x-sum)%n+2*n-1)%n+1;
}
int main(){
//	freopen("testdata.in","r",stdin); 
	n=read(),m=read(); 
	rep(i,1,n) b[i]=read(); 
	a[1].l=1,a[1].r=n; 
	build(1); Q=read(); 
	int x,y,k; 
	while (Q--){
		scanf("%s",ch); 
		if (ch[0]=='R') {
			k=read(); 
			if (flag) sum-=k; else sum+=k; 
		}
		if (ch[0]=='F') flag^=1; 
		if (ch[0]=='S') {
			x=get(),y=get(); 
			Swap(x,y); 
		}
		if (ch[0]=='P') {
			x=get(),y=get(),k=read(); 
			if (flag) swap(x,y); 
			if (x<=y) changes(1,x,y,k); 
			else changes(1,1,y,k),changes(1,x,n,k); 
		}
		if (ch[0]=='C'&&ch[1]=='S'){
			x=get(),y=get(); 
			if (flag) swap(x,y); 
			if (x<=y) printf("%d\n",ask(1,x,y)); else {
				int ans=ask(1,1,y)+ask(1,x,n); 
				if (a[1].lv==a[1].rv) ans--; 
				printf("%d\n",ans); 
			}
		}
		if (ch[0]=='C' && ch[1]!='S')
		{
			int ans=ask(1,1,n);
			if (a[1].lv==a[1].rv&&ans!=1) ans--;
			printf("%d\n",ans); 
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值