Tunnel Warfare --HDU1540&POJ2892(简单的暴力分块替换线段树区间合并)

Tunnel Warfare

Time Limit: 1000MS   Memory Limit: 131072K

题目链接http://poj.org/problem?id=2892

Description

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!

Input

The first line of the input contains two positive integers n and m (nm ≤ 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:

  1. D x: The x-th village was destroyed.
  2. Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.
  3. R: The village destroyed last was rebuilt.

 

Output

Output the answer to each of the Army commanders’ request in order on a separate line.

Sample Input

7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4

Sample Output

1
0
2
4

Hint

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]
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

你可能感兴趣的:(#,分块)