java 线段树 区间更新_POJ 3225 线段树区间更新(两种更新方式)

http://blog.csdn.net/niuox/article/details/9664487

这道题明显是线段树,根据题意可以知道:

(用0和1表示是否包含区间,-1表示该区间内既有包含又有不包含)

U:把区间[l,r]覆盖成1

I:把[-∞,l)(r,∞]覆盖成0

D:把区间[l,r]覆盖成0

C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换

S:[l,r]区间0/1互换

这里有两个地方和区间更新不一样

一个是会更新选中区间以外的所有区域,可以这样子解决:

void update(char val,int L,int R,int l,int r,intrt)

{

...int mid = (l + r)>>1;if (L <=mid)

{

update(val,L,R,l,mid,rt<<1);

}else if(val == 'I' || val == 'C')

{

a[rt<<1] = col[rt<<1] = 0;

}if(R >mid)

{

update(val,L,R,mid+1,r,rt<<1|1);

}else if(val == 'I' || val == 'C')

{

a[rt<<1|1] = col[rt<<1|1] = 0;

}

}

if判断左边是否小于mid,如果不是,那么更新它的左边就是我们想要的选中区域外了,右边同理。

第二个是有两种更新方式,覆盖和异或

这种问题一般需要两种标记,但这里其中一种是覆盖,所以一种标记可以用值自身表示,-1表示杂,非-1表示纯。一个标记数组就行。

然后还要理清两种标记使用的方式

很明显我们可以知道这个性质:

当一个区间被覆盖后,不管之前有没有异或标记都没有意义了

所以当一个节点得到覆盖标记时把异或标记清空

第三种是开闭区间,这里可以通过把所有数乘2处理(偶数表示端点,奇数表示两端点间的区间)。

#include #include#include#include#include#include#include#include#include#include#include#include#include#include#include

using namespacestd;#define mem(a,b) memset(a,b,sizeof(a))

#define pf printf

#define sf scanf

#define spf sprintf

#define pb push_back

#define debug printf("!\n")

#define MAXN 65535*2

#define MAX(a,b) a>b?a:b

#define blank pf("\n")

#define LL long long

#define ALL(x) x.begin(),x.end()

#define INS(x) inserter(x,x.begin())

#define pqueue priority_queue

#define INF 0x3f3f3f3f

intn,m;int a[MAXN<<4],col[MAXN<<4],ans;boolvis[MAXN];void FXOR(intx)

{if(a[x]!=-1) a[x]^=1;else col[x]^=1;

}void PushDown(intrt)

{if(a[rt] != -1)

{

a[rt<<1] = a[rt<<1|1] =a[rt];

col[rt<<1] = col[rt<<1|1] = 0;

a[rt]= -1;

}if(col[rt])

{

FXOR(rt<<1);

FXOR(rt<<1|1);

col[rt]= 0;

}

}void update(char val,int L,int R,int l,int r,intrt)

{if(L <= l && r <=R)

{if(val == 'U')

{

a[rt]= 1;

col[rt]= 0;

}else if(val == 'D')

{

a[rt]= col[rt] = 0;

}else if(val == 'C' || val == 'S')

{

FXOR(rt);

}return;

}

PushDown(rt);int mid = (l + r)>>1;if (L <=mid)

{

update(val,L,R,l,mid,rt<<1);

}else if(val == 'I' || val == 'C')

{

a[rt<<1] = col[rt<<1] = 0;

}if(R >mid)

{

update(val,L,R,mid+1,r,rt<<1|1);

}else if(val == 'I' || val == 'C')

{

a[rt<<1|1] = col[rt<<1|1] = 0;

}

}void query(int l,int r,intrt)

{if(a[rt] == 1)

{for(int i = l;i<=r;i++) vis[i] = true;return;

}else if(a[rt] == 0) return;if(l == r) return;

PushDown(rt);int mid = (l + r)>>1;

query(l,mid,rt<<1);

query(mid+1,r,rt<<1|1);

}intmain()

{intr,t;charop,lchar,rchar;

a[1] = col[1] = 0;while(~sf("%c %c%d,%d%c\n",&op,&lchar,&r,&t,&rchar))

{

r<<=1;

t<<=1;if(lchar == '(') r++;if(rchar == ')') t--;

update(op,r,t,0,MAXN,1);

}

query(0,MAXN,1);int s = -1,e;bool flag = false;for(int i=0;i<=MAXN;i++)

{if(vis[i])

{if(s == -1) s =i;

e=i;

}else{if(s!=-1)

{if(flag) pf(" ");

pf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']');

s= -1;

flag= true;

}

}

}if(!flag) printf("empty set");return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值