SDOI2008校门外的区间

这道题作为前天的模拟赛题,考场上我在还剩一个半小时的情况下居然选择求稳打暴力,水过了40分,然后就坐看cansult和refun这俩dalaoAK...

一开始我的想法是,把区间看成两点之间不包含端点的小区间和端点构成的集合,然后分开处理,这个做法可能暴力还是可以的,然而如果要用线段树的话,就要开两颗线段树

正确做法应该是把每个点拆成三个点,)就是标记第一个点,】和【就是标记第二个点,(就是标记第三个点

然后我还把数据范围>=0看成>=1,最后的输出也很容易出错

#include<iostream>
#include<cstdio>
#include<cstring>
#define ls ((root<<1)+1)
#define rs ((root<<1)+2)
#define mid ((l+r)>>1)
using namespace std;
int N,n,a[400000];
struct order{
	int type,l,r;
}q[200001];
struct Node{
	int mul,add;
}tree[2000000];
void init(){
	char ch; int l,r;
	while (cin>>ch){
	n++;
	if (ch=='U') q[n].type=1;
	if (ch=='I') q[n].type=2;
	if (ch=='D') q[n].type=3;
	if (ch=='C') q[n].type=4;
	if (ch=='S') q[n].type=5;
	cin>>ch>>l;
	l=l*3+2+(ch=='(');
	cin>>ch>>r>>ch; 
	r=r*3+2-(ch==')');
	q[n].l=l; q[n].r=r;
	N=max(N,q[n].r);
	}
}
void pushdown(int root){
	tree[ls].add=tree[root].mul*tree[ls].add+tree[root].add;
	tree[rs].add=tree[root].mul*tree[rs].add+tree[root].add;
	tree[ls].mul*=tree[root].mul;
	tree[rs].mul*=tree[root].mul;
	tree[root].add=0;
	tree[root].mul=1;
}
void Mul(int root,int l,int r,int l1,int r1,int val){
	if (l>=l1&&r<=r1){;
		tree[root].mul*=val;
		tree[root].add*=val; 
		return;
	}
	pushdown(root);
	if (l1<=mid) Mul(ls,l,mid,l1,r1,val);
	if (r1>mid) Mul(rs,mid+1,r,l1,r1,val);
}
void Add(int root,int l,int r,int l1,int r1,int val){
	if (l>=l1&&r<=r1){;
		tree[root].add+=val; 
		return;
	}
	pushdown(root);
	if (l1<=mid) Add(ls,l,mid,l1,r1,val);
	if (r1>mid) Add(rs,mid+1,r,l1,r1,val);
}
int query(int root,int l,int r,int pos){
	if (l==r) return tree[root].add;
	pushdown(root);
	if (pos<=mid) return query(ls,l,mid,pos);
	else return query(rs,mid+1,r,pos);
}
void build(int root,int l,int r){
	tree[root].mul=1;
	if (l==r){
		tree[root].add=-1;
		return;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
}
int main(){
	init();
	int i,l,r,j;
	build(0,0,N);
	for (i=1;i<=n;i++){
		if (q[i].type==1){
			Mul(0,0,N,q[i].l,q[i].r,0);
			Add(0,0,N,q[i].l,q[i].r,1);
			continue;
		}
		if (q[i].type==2){
			if (q[i].l>=1) {
			    Mul(0,0,N,1,q[i].l-1,0);
				Add(0,0,N,1,q[i].l-1,-1);
			}
			if (q[i].r<N){
				Mul(0,0,N,q[i].r+1,N,0);
				Add(0,0,N,q[i].r+1,N,-1);
			}
			continue;
		}
		if (q[i].type==3){
			Mul(0,0,N,q[i].l,q[i].r,0);
			Add(0,0,N,q[i].l,q[i].r,-1);
			continue;
		}
		if (q[i].type==4){
			if (q[i].l>=1) {
			    Mul(0,0,N,1,q[i].l-1,0);
				Add(0,0,N,1,q[i].l-1,-1);
			}
			if (q[i].r<N){
				Mul(0,0,N,q[i].r+1,N,0);
				Add(0,0,N,q[i].r+1,N,-1);
			}
			Mul(0,0,N,q[i].l,q[i].r,-1);
			continue;
		}
		Mul(0,0,N,q[i].l,q[i].r,-1);
	}
	bool flag=1;
	for (i=1;i<=N;i++){
	  a[i]=query(0,0,N,i);
	  if (a[i]==1) flag=0;
	}
	if (flag){
		cout<<"empty set";
		return 0;
	}
	a[N+1]=-1;
	for (i=1;i<=N;i++){
		if (a[i]==-1) continue;
		l=i;
		for (i=l+1;i<=N+1;i++)//这个地方要开到N+1,因为如果开到N,a[N]!=-1时会出错 
		  if (a[i]==-1) break;
		r=--i;
		char c1=(l%3==2)?'[':'(',c2=(r%3==2)?']':')';
		printf("%c%d,%d%c ",c1,(l-1)/3,(r-1)/3,c2);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值