luoguP2161 [SHOI2009]会场预约

luoguP2161 [SHOI2009]会场预约

好久没打线段树了...为不会做找借口

https://www.luogu.org/problem/P2161

题意:

大概是说,一开始全空序列,之后开始安排招待会议,输入有q个操作,分两种:

A l r : 将[l , r]占了,以前在 【l , r】的会议取消,并输出取消会议的个数

B : 输入当前存在的会议

首先我们需要理清问题的实质:这里我们将每个会议看成一个颜色
操作A实质:查询一段区间内有多少种颜色,再清空这区间里的每种颜色所属的区域,再在这一区间填上另一种颜色

其实就是一个删除操作难想,其实不用真正的删除,用一个del[]记录每种颜色是否被删,然后在更新A,B操作答案的时候判一下就行了
因题而异吧

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAX = 200000+99;

int q;
struct tree{
	int is, set;
	//is:区间o是否为一种颜色 
}tr[MAX<<2];
int del[MAX], del_n, ans;
//ans表示还剩颜色数,del_n表示每次删除颜色的数目,del保存该颜色是否已经被清除 

void build(int o, int l, int r) {
	tr[o].is = 1, tr[o].set = 0;
	if(l == r) return ;
	int mid = (l+r)>>1;
	build(o<<1, l, mid);
	build(o<<1|1, mid+1, r);
}

void pushdown(int o) {
	tr[o].is = 0;//下放后该区间颜色不一 (要先写这个!!,因为可能它没有set,但是却为不同颜色 
	if(tr[o].set == 0) return ;
	tr[o<<1].set = tr[o<<1|1].set = tr[o].set;
	tr[o<<1].is = tr[o<<1|1].is = 1;
	tr[o].set = 0;
}
void query(int o, int l, int r, int ql, int qr, int k) {
	if(tr[o].is) {
		if(tr[o].set!=0 && !del[tr[o].set]) --ans, ++del_n;//注意判无色
		del[tr[o].set] = 1;
		tr[o].set = k/*, tr[o].is = 1*/;
		return ;
	}
	int mid = (l+r)>>1;
	if(ql <= mid) query(o<<1, l, mid, ql, qr, k);
	if(mid < qr) query(o<<1|1, mid+1, r, ql, qr, k);//找到区间中颜色唯一的tr,并修改 
	tr[o].is = 1, tr[o].set = k;
}
void optset(int o, int l, int r, int ql, int qr, int k) {
	if(ql <= l && r <= qr) {query(o, l, r, ql, qr, k); return;}//找到要查询并修改的区间 
	int mid = (l+r)>>1;
	pushdown(o);
	if(ql <= mid) optset(o<<1, l, mid, ql, qr, k);
	if(mid < qr) optset(o<<1|1, mid+1, r, ql, qr, k);
}

struct tmp{
	int l, r;
	char ab;
}cmd[MAX];
int st = MAX, ed = -MAX;

int main() {
	scanf("%d",&q);
	for(int i = 1; i <= q; i++) {
		cin>>cmd[i].ab;
		if(cmd[i].ab == 'A') {
			scanf("%d%d",&cmd[i].l, &cmd[i].r);
			st = min(cmd[i].l, st), ed = max(ed, cmd[i].r);
		}
	}
	build(1, st, ed);
	int cnt = 0;//颜色序数 
	for(int i = 1; i <= q; i++) {
		if(cmd[i].ab == 'A') {
			++cnt, del_n = 0, ++ans;
			optset(1, st, ed, cmd[i].l, cmd[i].r, cnt);
			printf("%d
",del_n);
		} else printf("%d
",ans);
	}
	return 0; 
}
原文地址:https://www.cnblogs.com/tyner/p/11695360.html