BZOJ 1493 NOI 2007 项链工厂 Splay

题目大意:有一个很长的带颜色的项链,要求你快速的维护一种数据结构,他可以:

1.把序列的后k个放在前面。

2.将区间2~cnt的珠子翻转。

3.将位置i和位置j的珠子互换。

4.将区间i到j染色成k

5.输出整个序列的颜色块的个数

6.输出从i到j的颜色块的个数。

思路:Splay。有些不好处理的是要时刻想着这是一个环,所以所有的计算颜色块的个数的时候要考虑收尾的颜色是否相同。还有从序列的尾部到转一圈回去的情况。

就因为这个题我的代码有个小小小小的问题,花了仨小时的时间带着数据才把错找到。。简直不知道说些什么好。。啊啊啊啊以后写题一定要细致啊!!!

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 500010
using namespace std;

struct Complex{
	int col,cnt_col,l_col,r_col;
	int size;
	Complex *son[2],*father;

	bool reverse,change;
	int change_into;

	void Combine(Complex *a,bool dir) {
		son[dir] = a;
		a->father = this;
	}
	bool Check() {
		return father->son[1] == this;
	}

	void Reverse();
	void Paint(int val);

	void PushUp();
	void PushDown();
}*nil = new Complex(),*root;

int cnt,cols,asks;
int src[MAX];

char cmd[10];

void Pretreatment();

inline Complex *NewComplex(int val);
Complex *BuildTree(int l,int r);
Complex *Kth(Complex *a,int k);

inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
inline void SplaySeg(int x,int y);

int main()
{
	Pretreatment();
	cin >> cnt >> asks;
	for(int i = 1;i <= cnt; ++i)
		scanf("%d",&src[i]);
	root = BuildTree(0,cnt + 1);
	root->father = nil;
	cin >> asks;
	for(int x,y,z,i = 1;i <= asks; ++i) {
		scanf("%s",cmd);
		if(cmd[0] == 'R') {
			scanf("%d",&x);
			SplaySeg(cnt - x + 1,cnt);
			Complex *temp = root->son[1]->son[0];
			temp->father = nil;
			root->son[1]->son[0] = nil;
			root->son[1]->PushUp(),root->PushUp();
			Splay(Kth(root,1),nil);
			Splay(Kth(root,2),root);
			root->son[1]->Combine(temp,false);
		}
		else if(cmd[0] == 'F') {
			SplaySeg(2,cnt);
			root->son[1]->son[0]->Reverse();
		}
		else if(cmd[0] == 'S') {
			scanf("%d%d",&x,&y);
			if(x == y)	continue;
			if(x > y)	swap(x,y);
			Splay(Kth(root,x + 1),nil);
			Splay(Kth(root,y + 1),root);
			int temp = root->son[1]->col;
			root->son[1]->col = root->col;
			root->son[1]->PushUp(),root->PushUp();
			root->col = temp;
		}
		else if(cmd[0] == 'P') {
			scanf("%d%d%d",&x,&y,&z);
			if(y >= x) {
				SplaySeg(x,y);
				root->son[1]->son[0]->Paint(z);
			}
			else {
				SplaySeg(x,cnt);
				root->son[1]->son[0]->Paint(z);
				root->son[1]->PushUp(),root->PushUp();
				SplaySeg(1,y);
				root->son[1]->son[0]->Paint(z);
			}
		}
		else if(cmd[0] == 'C' && cmd[1] == '\0') {
			SplaySeg(1,cnt);
			int ans = root->son[1]->son[0]->cnt_col;
			ans -= (root->son[1]->son[0]->l_col == root->son[1]->son[0]->r_col);
			if(!ans)	++ans;
			printf("%d\n",ans);
			continue;
		}
		else {
			scanf("%d%d",&x,&y);
			if(y >= x) {
				SplaySeg(x,y);
				printf("%d\n",root->son[1]->son[0]->cnt_col);
			}
			else {
				int ans = 0;
				SplaySeg(x,cnt);
				ans = root->son[1]->son[0]->cnt_col;
				SplaySeg(1,y);
				ans += root->son[1]->son[0]->cnt_col;
				SplaySeg(1,cnt);
				ans -= (root->son[1]->son[0]->l_col == root->son[1]->son[0]->r_col);
				printf("%d\n",ans);
			}
			continue;
		}
		root->son[1]->PushUp(),root->PushUp();
	}
	return 0;
}

void Complex:: Reverse()
{
	if(!col)	return ;
	reverse ^= 1;
	swap(son[0],son[1]);
	swap(l_col,r_col);
}

void Complex:: Paint(int val)
{
	if(!col)	return ;
	change = true;
	change_into = val;
	l_col = r_col = col = val;
	cnt_col = 1;
}

void Complex:: PushUp()
{
	if(this == nil)	return ;
	size = son[0]->size + son[1]->size + 1;
	if(!col)	return ;
	cnt_col = 1;
	l_col = r_col = col;
	if(son[0]->col) {
		cnt_col += son[0]->cnt_col - (son[0]->r_col == col);
		l_col = son[0]->l_col;
	}
	if(son[1]->col) {
		cnt_col += son[1]->cnt_col - (son[1]->l_col == col);
		r_col = son[1]->r_col;
	}
}

void Complex:: PushDown()
{
	if(this == nil)	return ;
	if(reverse) {
		son[0]->Reverse();
		son[1]->Reverse();
		reverse = false;
	}
	if(change) {
		son[0]->Paint(change_into);
		son[1]->Paint(change_into);
		change = false;
	}
}	

void Pretreatment()
{
	nil->size = 0;
	nil->col = nil->l_col = nil->r_col = 0;
	nil->cnt_col = 0;
	nil->father = nil->son[0] = nil->son[1] = nil;
}

inline Complex *NewComplex(int val)
{
	Complex *re = new Complex();
	re->col = re->l_col = re->r_col = val;
	re->size = 1;
	if(val)	 re->cnt_col = 1;
	re->son[0] = re->son[1] = nil;
	return re;
}

Complex *BuildTree(int l,int r)
{
	if(l > r)	return nil;
	int mid = (l + r) >> 1;
	Complex *re = NewComplex(src[mid]);
	re->Combine(BuildTree(l,mid - 1),false);
	re->Combine(BuildTree(mid + 1,r),true);
	re->PushUp();
	return re;
}

Complex *Kth(Complex *a,int k)
{
	a->PushDown();
	if(a->son[0]->size >= k)	return Kth(a->son[0],k);
	k -= a->son[0]->size;
	if(k == 1)	return a;
	return Kth(a->son[1],k - 1);
}

inline void Rotate(Complex *a,bool dir)
{
	Complex *f = a->father;
	f->PushDown(),a->PushDown();
	f->son[!dir] = a->son[dir];
	f->son[!dir]->father = f;
	a->son[dir] = f;
	a->father = f->father;
	f->father->son[f->Check()] = a;
	f->father = a;
	f->PushUp();
	if(root == f)	root = a;
}

inline void Splay(Complex *a,Complex *aim)
{
	while(a->father != aim) {
		if(a->father->father == aim)
			Rotate(a,!a->Check());
		else if(!a->father->Check()) {
			if(!a->Check())
				Rotate(a->father,true),Rotate(a,true);
			else	Rotate(a,false),Rotate(a,true);
		}
		else {
			if(a->Check())
				Rotate(a->father,false),Rotate(a,false);
			else	Rotate(a,true),Rotate(a,false);
		}
	}
	a->PushUp();
}

inline void SplaySeg(int x,int y)
{
	x++,y++;
	Splay(Kth(root,x - 1),nil);
	Splay(Kth(root,y + 1),root);
}
时间: 2024-07-31 10:09:41

BZOJ 1493 NOI 2007 项链工厂 Splay的相关文章

【BZOJ 1493】[NOI2007]项链工厂

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 992  Solved: 454 [Submit][Status] Description   Input 输入文件第一行包含两个整数N, c,分别表示项链包含的珠子数目以及颜色 数目.第二行包含N 个整数,x1, x2-, xn,表示从位置1 到位置N 的珠子的颜色, 1 ≤ xi ≤ c.第三行包含一个整数Q,表示命令数目.接下来的Q 行每行一条命令, 如上

【BZOJ-1493】项链工厂 Splay

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1440  Solved: 626[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系统包括硬件系统与软件系统,软件系统与用户进行交互并控制

BZOJ 1500 NOI 2005 维修数列 Splay

题意:见下图 传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好.. 这个题对Splay的所有操作基本是全了. 插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上. 删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉.(这里可以用数组优化,可以避免递归free节省时间) 修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换. 求和:维护

[BZOJ 1491] [NOI 2007] 社交网络

好吧先不吐槽这道题的题目是一部介绍facebook的电影…… 1491: [NOI2007]社交网络 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1010  Solved: 584[Submit][Status][Discuss] Description Input Output 输出文件包括n 行,每行一个实数,精确到小数点后3 位.第i 行的实数表 示结点i 在社交网络中的重要程度. Sample Input 4 4 1 2 1 2 3 1

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

bzoj 1493: [NOI2007]项链工厂(线段树)

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1256  Solved: 545[Submit][Status][Discuss] Description Input 输 入文件第一行包含两个整数N, c,分别表示项链包含的珠子数目以及颜色 数目.第二行包含N 个整数,x1, x2…, xn,表示从位置1 到位置N 的珠子的颜色, 1 ≤ xi ≤ c.第三行包含一个整数Q,表示命令数目.接下来的Q 行每行一

数据结构(Splay平衡树): [NOI2007] 项链工厂

[NOI2007] 项链工厂 ★★★   输入文件:necklace.in   输出文件:necklace.out   简单对比 时间限制:4 s   内存限制:512 MB [问题描述] T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱.最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链. 该项链自助生产系统包括硬件系统与软件系统,软件系统与用户进行交互并控制硬件系统,硬件系统接受软件系统的命令生产指定的项链.该

BZOJ1493 [NOI2007]项链工厂

未完待续... 1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1320  Solved: 576[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系 统包括硬件系统与软件系统,软件系统与

bzoj1493[NOI2007]项链工厂 线段树

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1712  Solved: 723[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系 统包括硬件系统与软件系统,软件系统与用户进行交互并控