线段树专辑 —— pku 3225 Help with Intervals

http://poj.org/problem?id=3225

这题很有意思,对于[0,65535]这么一个区间,初始值为0,问最后为连续1的子区间有哪些。

很有趣的是,这题涉及到了开区间和闭区间,即() 和 [] 。确是比较棘手!

解决的办法是将所给的数据范围乘以2,然后根据给的是开区间或则是闭区间修改数据,例如:给你(2,3]这样的数据,如何处理呢?

我们将范围乘以2,得到(4,6],然后,如果左边是开区间,则将4加1,得到5,同理,如果右边是开区间,则将6减去一个1。

为什么这样做呢? 看看,因为数据乘以2后,得到的结果一定是偶数,而偶数加一减一后,肯定得到奇数。也就是说,如果最后得到的数据是偶数,那就是闭区间,如果得到的数据是奇数,那就对应着开区间。

 

再来分析一下5个基本操作:

U操作最简单了,只需要将T的区间范围在线段树中跟新为1即可

D操作一样简单,只需要将T的区间范围在线段树中跟新为0即可

S操作:将T区间范围在线段树中取反(1->0,0->1)为什么这样做呢?着不是异或吗,怎么变成取反了?仔细分析一下便知道,因为T的数据全是1,1^1=0,1^0=1,这不就是取反吗?!

I操作:假设T区间为[a,b],那么将区间[0,a-1]和区间[b+1,max]跟新为0即可,为什么呢?因为T全是1,s集合和T取交的话还是等于s。

C操作:假设T区间为[a,b],那么先将将区间[0,a-1]和区间[b+1,max]跟新为0,再对区间[a,b]取反,为什么?最后一个了,自己想想呗~

 

View Code
  1 #include<iostream>
2 #include<string>
3 #include<cmath>
4 #include<algorithm>
5 using namespace std;
6
7 #define inf 65535
8
9 struct node
10 {
11 int l;
12 int r;
13 int cover; //记录线段是单色还是混色
14 int change; //是否需要取反
15 void changeedit()
16 {
17 if(cover!=-1) //如需要取反,而线段又是单色,则直接取反
18 cover^=1;
19 else
20 change^=1; //否则在原先需要取反的基础上再取反
21 }
22 };
23
24 node tree[1000000];
25
26 void build(int i,int l,int r)
27 {
28 tree[i].l=l;
29 tree[i].r=r;
30 tree[i].cover=0;
31 tree[i].change=0;
32 if(l==r)
33 return;
34 int mid=(l+r)/2;
35 build(2*i,l,mid);
36 build(2*i+1,mid+1,r);
37 }
38
39 void updata(int i,int l,int r,int w) //直接更新覆盖
40 {
41 if(tree[i].l>r || tree[i].r<l)
42 return;
43 if(tree[i].l>=l && tree[i].r<=r)
44 {
45 tree[i].cover=w;
46 tree[i].change=0;
47 return;
48 }
49 if(tree[i].cover!=-1) //混色,向下传递
50 {
51 tree[2*i].cover=tree[2*i+1].cover=tree[i].cover;
52 tree[2*i].change=tree[2*i+1].change=tree[i].change;
53 tree[i].cover=-1;
54 tree[i].change=0;
55 }
56 if(tree[i].change) //需要取反,则其子区间便取反
57 {
58 tree[2*i].changeedit();
59 tree[2*i+1].changeedit();
60 tree[i].change=0; //标记取消
61 }
62 updata(2*i,l,r,w);
63 updata(2*i+1,l,r,w);
64 if(tree[2*i].cover==tree[2*i+1].cover) //回溯标记颜色
65 tree[i].cover=tree[2*i].cover;
66 else
67 tree[i].cover=-1;
68 }
69
70 void updatas(int i,int l,int r) //取反
71 {
72 if(tree[i].l>r || tree[i].r<l)
73 return;
74 if(tree[i].l>=l && tree[i].r<=r)
75 {
76 if(tree[i].cover!=-1)
77 tree[i].cover^=1;
78 else
79 tree[i].change^=1;
80 return;
81 }
82 if(tree[i].cover!=-1)
83 {
84 tree[2*i].cover=tree[2*i+1].cover=tree[i].cover;
85 tree[2*i].change=tree[2*i+1].change=tree[i].change;
86 tree[i].cover=-1;
87 tree[i].change=0;
88 }
89 if(tree[i].change)
90 {
91 tree[2*i].changeedit();
92 tree[2*i+1].changeedit();
93 tree[i].change=0;
94 }
95 updatas(2*i,l,r);
96 updatas(2*i+1,l,r);
97 if(tree[2*i].cover==tree[2*i+1].cover)
98 tree[i].cover=tree[2*i].cover;
99 else
100 tree[i].cover=-1;
101 }
102
103 int v[2*inf+2];
104
105 void find(int i,int l,int r)
106 {
107 if(tree[i].l>r || tree[i].r<l)
108 return;
109 if(tree[i].l==tree[i].r)
110 {
111 v[tree[i].l]=tree[i].cover;
112 return;
113 }
114 if(tree[i].cover!=-1)
115 {
116 tree[2*i].cover=tree[2*i+1].cover=tree[i].cover;
117 tree[2*i].change=tree[2*i+1].change=tree[i].change;
118 tree[i].cover=-1;
119 tree[i].change=0;
120 }
121 if(tree[i].change)
122 {
123 tree[2*i].changeedit();
124 tree[2*i+1].changeedit();
125 tree[i].change=0;
126 }
127 find(2*i,l,r);
128 find(2*i+1,l,r);
129 return ;
130 }
131
132 int main()
133 {
134 //freopen("in.txt","r",stdin);
135 char c,l,r;
136 int a,b,max=0,i,j;
137 build(1,0,2*inf);
138 while(~scanf("%c %c%d,%d%c\n", &c, &l, &a, &b, &r))
139 {
140 a*=2; b*=2;
141 if(l=='(')
142 a++;
143 if(r==')')
144 b--;
145 if(a>max)
146 max=a;
147 if(b>max)
148 max=b;
149 if(a>b)
150 continue;
151 if(c=='U')
152 {
153 updata(1,a,b,1);
154 }
155 else if(c=='D')
156 {
157 updata(1,a,b,0);
158 }
159 else if(c=='S')
160 {
161 updatas(1,a,b);
162 }
163 else if(c=='C')
164 {
165 updatas(1,a,b);
166 updata(1,0,a-1,0);
167 updata(1,b+1,max,0);
168 }
169 else
170 {
171 updata(1,0,a-1,0);
172 updata(1,b+1,max,0);
173 }
174 }
175 find(1,0,max);
176 int flag=0;
177 for(i=0;i<=max;i++) //查找有多少连续的1
178 {
179 if(v[i])
180 {
181 for(j=i+1;j<=max;j++)
182 {
183 if(!v[j])
184 break;
185 }
186 b=j-1;
187 if(flag)
188 printf("");
189 printf("%c%d,%d%c",i%2==1?'(':'[',i%2==1?(i-1)/2:i/2,b%2==1?(b+1)/2:b/2,b%2==1?')':']');
190 flag=1;
191 i=j;
192 }
193 }
194 if(!flag)
195 {
196 printf("empty set");
197 }
198 cout<<endl;
199 return 0;
200 }



posted @ 2011-11-14 10:17  Accept  阅读(247)  评论(0编辑  收藏  举报