[BZOJ]1493 [NOI2007]项链工厂 线段树

本文针对NOI2007项链工厂问题,详细介绍了如何利用线段树解决项链颜色修改及查询任务,通过记录珠子顺序变化,实现了高效操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1493: [NOI2007]项链工厂

Time Limit: 30 Sec   Memory Limit: 64 MB
Submit: 1647   Solved: 704
[ Submit][ Status][ Discuss]

Description

T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖、款式多样、价格适中,广受青年人的喜爱。
最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链。该项链自助生产系
统包括硬件系统与软件系统,软件系统与用户进行交互并控制硬件系统,硬件系统接受软件系统的命令生产指定的
项链。该系统的硬件系统已经完成,而软件系统尚未开发,T公司的人找到了正在参加全国信息学竞赛的你,你能
帮助T公司编写一个软件模拟系统吗?一条项链包含 N 个珠子,每个珠子的颜色是 1,2,…,c 中的一种。项链
被固定在一个平板上,平板的某个位置被标记位置 1 ,按顺时针方向其他位置被记为 2,3,…,N。
你将要编写的软件系统应支持如下命令:

Input

输入文件第一行包含两个整数 N,c ,分别表示项链包含的珠子数目以及颜色数目。
第二行包含 N 个整数,x1,x2,…,xn ,表示从位置 1 到位置 N 的珠子的颜色,1≤xi≤c 。
第三行包含一个整数 Q ,表示命令数目。接下来的 Q 行每行一条命令,如上文所述。N≤500000 ,Q≤500000,c≤1000 

Output

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

Sample Input

5 3
1 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1

Sample Output

4
1

HINT

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

链上的位置编号如图1:



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

如图4所示。

2. 关于CountSegment命令CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度

等于 N 时,我们仍然将查询部分作为“线段”理解。例如在图4所示的情况中,执行“CS 1 10”命令,查询从位

置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是

,若执行“C”命令,返回值则为 2

Source

[ Submit][ Status][ Discuss]


HOME Back

  一看到翻转就想到splay, 于是踏上了不归路...说真的这道题的splay比维修数列的还要难写...特判一抹多. 调了我一下午... 机房又热, 做的毛焦火辣...以后能用线段树做的绝对绝对不用splay做, 太恶心了...

讲一下线段树的做法. 可以发现无论怎么变换修改, 实际上珠子的顺序是不变的. 那么记录一下移动的变化, 就可以在线段树上操作了. 记录一个mov即可 -- 因为每次修改(除了交换颜色)都是对所有珠子的移动.

线段树和splay的差距(下面的那个是线段树).

2312509MaxMercer1493Accepted22792 kb23512 msC++/Edit4957 B2017-09-25 16:54:03

RunIDUserProblemResultMemoryTimeLanguageCode_LengthSubmit_Time
2312881MaxMercer1493Accepted49648 kb2488 msC++/Edit3589 B2017-09-25 18:38:21


线段树虽然常数不小但是比起splay还是好得多啊...

#include<stdio.h>
#include<algorithm>
#define Mercer register int
using namespace std;
const int maxn = 500005;
char ss[2];
int rev, mov, n, mx, q, a[maxn];
inline const int read(){
	register int x = 0;
	register char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}
inline int ori(int x){
	if(rev) x = n - x + 2;
	x -= mov;
	for(; x > n; x -= n);
	for(; x < 1; x += n);
	return x;
}
struct node{
	node *ls, *rs;
	int sum, lc, rc, tag;
	inline void pushdown(){
		if(tag){
			ls->tag = rs->tag = tag;
			ls->lc  = ls->rc  = rs->lc = rs->rc = tag;
			ls->sum = rs->sum = 1;
			tag = 0;
		}
	}
	inline void update(){
		lc = ls->lc, rc = rs->rc;
		sum = ls->sum + rs->sum - (ls->rc == rs->lc);
	}
}pool[maxn * 4], *tail = pool, *root;
node *build(int lf, int rg){
	node *bt = ++tail;
	if(lf == rg) { bt->lc = bt->rc = bt->tag = a[lf]; bt->sum = 1; return bt;}
	int mid = (lf + rg) >> 1;
	bt->ls = build(lf, mid), bt->rs = build(mid + 1, rg);
	bt->update(); return bt;
}
int query(node* bt, int lf, int rg, int pos){
	if(lf == rg) return bt->lc;
	int mid = (lf + rg) >> 1;
	bt->pushdown();
	if(pos <= mid) return query(bt->ls, lf, mid, pos);
	else return query(bt->rs, mid + 1, rg, pos);
}
void modify(node* bt, int lf, int rg, int L, int R, int col){
	if(L <= lf && rg <= R) {bt->lc = bt->rc = bt->tag = col; bt->sum = 1; return;}
	int mid = (lf + rg) >> 1;
	bt->pushdown();
	if(L <= mid) modify(bt->ls, lf, mid, L, R, col);
	if(R > mid) modify(bt->rs, mid + 1, rg, L, R, col);
	bt->update();
}
int query_seg(node* bt, int lf, int rg, int L, int R){
	if(L <= lf && rg <= R) return bt->sum;
	int mid = (lf + rg) >> 1, rt1 = 0, rt2 = 0, ed = 0;
	bt->pushdown();
	if(L <= mid) rt1 = query_seg(bt->ls, lf, mid, L, R);
	if(R > mid) rt2 = query_seg(bt->rs, mid + 1, rg, L, R);
	ed = rt1 + rt2;
	if(rt1 && rt2 && bt->ls->rc == bt->rs->lc) ed--;
	return ed; 
}
int main(){
	n = read(), mx = read();
	for(Mercer i = 1; i <= n; ++i) a[i] = read();
	root = build(1, n);
	q = read();
	for(Mercer i = 1; i <= q; ++i){
		scanf("%s", ss);
		if(ss[0] == 'R'){
			int x = read();
			mov += (rev) ? (-x) : x;
			for(; mov > n; mov -= n);
			for(; mov < 0; mov += n);
			continue;
		}
		if(ss[0] == 'F') {rev ^= 1; continue;}
		if(ss[0] == 'S'){
			int x = read(), y = read();
			x = ori(x), y = ori(y);
			int colx = query(root, 1, n, x), coly = query(root, 1, n, y);
			modify(root, 1, n, x, x, coly), modify(root, 1, n, y, y, colx);
			continue;
		}
		if(ss[0] == 'P'){
			int x = read(), y = read(), col = read();
			x = ori(x), y = ori(y);
			if(rev) swap(x, y);
			if(x > y) modify(root, 1, n, x, n, col), modify(root, 1, n, 1, y, col);
			else modify(root, 1, n, x, y, col);
			continue;
		}
		if(ss[0] == 'C' && ss[1] == 'S'){
			int x = read(), y = read(), ans = 0;
			x  = ori(x), y = ori(y);
			if(rev) swap(x, y);
			if(x <= y) ans = query_seg(root, 1, n, x, y);
			else ans = query_seg(root, 1, n, x, n) + query_seg(root, 1, n, 1, y) - (root->lc == root->rc);
			printf("%d\n", ans); continue;
		}
		if(ss[0] == 'C'){
			int ans = root->sum;
			if(ans > 1 && root->lc == root->rc) ans--;
			printf("%d\n", ans);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值