Time Limit: 1000MS | Memory Limit: 131072K |
题目链接http://poj.org/problem?id=2892
During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.
Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.
There are three different events described in different format shown below:
Output the answer to each of the Army commanders’ request in order on a separate line.
7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
1 0 2 4
An illustration of the sample input:
OOOOOOO D 3 OOXOOOO D 6 OOXOOXO D 5 OOXOXXO R OOXOOXO R OOXOOOO
题目大意:给你n个村庄,让有三种操作,D x代表毁灭第x个村庄,R代表重建最后一个毁灭的村庄,Q x代表一次询问,问与x联通的有多少个村庄。。。看Hint应该很容易理解了
博主一看到题目就想到了分块。。。分块的话就很好处理,果然线段树还是不过关QAQ网上倒是有挺多区间合并的题解,我这里就写一下分块的题解吧。
将n个村庄分完块后,之后每一次毁灭操作,我们对x所处的块进行标记+1,然后将a[x]=0,并用栈存下x这个位置。恢复操作的时候取出栈顶元素,将块的标记-1,a[x]=1。重点就是查询操作了,查询的时候我们可以从x开始拓展,如果x所处的块有标记的话,我们就再这个快里面先找:
if (f[pos]) {
for (int i=x-1; i>=L[pos]; i--) {
if (!a[i]) {
markl=1;//标记找到了左端点
posl=i+1;//记录左端点的位置
break;
}
}
for (int i=x+1; i<=R[pos]; i++) {
if (!a[i]) {
markr=1;//右端点找到了
posr=i-1;//右端点的位置
break;
}
}
}
接下来如果说左标记没有的话就在pos(x所属的块)的前面找:
if (!markl) {
for (int i=pos-1; i>=1; i--) {
if (f[i]) {
for (int j=R[i]; j>=L[i]; j--) {
if (!a[j]) {markl=1;posl=j+1;break;}
}
break;
}
}
}
如果右标记没有的话就在pos的后面找,代码并没有什么改变。
最后特判两个标记存在与否,然后按照每种情况返回不同的值就好了。。。注意HDU的需要多组输入,真的非常坑QAQ
以下是AC代码:
#include
#include
#include
using namespace std;
const int mac=5e4+10;
int t;
int L[1000],R[1000],id[mac],a[mac];
int f[1000],des[mac],tot=0,n;
void destroy(int x)
{
int pos=id[x];
if (a[x]) f[pos]++,des[++tot]=x,a[x]=0;
}
int query(int x)
{
int pos=id[x];
if (!a[x]) return 0;
int posl=0,posr=0,markl=0,markr=0;
if (f[pos]){
for (int i=x-1; i>=L[pos]; i--){
if (!a[i]) {markl=1;posl=i+1;break;}
}
for (int i=x+1; i<=R[pos]; i++){
if (!a[i]) {markr=1;posr=i-1;break;}
}
}
if (!markl){
for (int i=pos-1; i>=1; i--){
if (f[i]){
for (int j=R[i]; j>=L[i]; j--){
if (!a[j]) {markl=1;posl=j+1;break;}
}
break;
}
}
}
if (!markr){
for (int i=pos+1; i<=t; i++){
if (f[i]){
for (int j=L[i]; j<=R[i]; j++){
if (!a[j]) {markr=1;posr=j-1;break;}
}
break;
}
}
}
if (!markr) {
if (!markl) return n;
return n-posl+1;
}
else {
if (markl) return posr-posl+1;
return posr;
}
}
void rebuild()
{
if (!tot) return;
int x=des[tot];
tot--;
a[x]=1;
f[id[x]]--;
}
void in(int &x)
{
int f=0;
char ch=getchar();
while (ch>'9' || ch<'0') ch=getchar();
while (ch>='0' && ch<='9') f=(f<<3)+(f<<1)+ch-'0',ch=getchar();
x=f;
}
int main()
{
int m;
in(n);in(m);
t=sqrt(n);
for (int i=1; i<=t; i++){
L[i]=(i-1)*t+1;
R[i]=i*t;
}
if (R[t]