Tunnel Warfare
Problem 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 (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:
D x: The x-th village was destroyed.
Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.
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
有三种操作 D X 毁灭X村庄,R 恢复最后毁灭的村庄 ,Q X 查询与X村庄相连接的村庄有多少。
这个题坑了我几天时间,说白了就是求区间范围,暴力肯定超时,很多关于区间的问题可以用线段树去解决,这题的难点在于巧妙的构造线段树。
定义结构体 三个变量 ll rl len 分别表示从左边区间开始最大的连续个数,从右区间开始最大的连续个数,这个节点区间的最大连续村庄数,父亲节点的最大连续数是max(左子节点最大连续数,右子节点最大连续数,左子节点rl+右子节点ll),左区间开始最大连续数是左子节点的ll,如果左子节点ll值为左子节点整个区间范围,那么父节点的ll的值等于原先的值加上右子节点的ll,父节点右区间开始最大连续数同理。
查询操作是 :假设查找的值k在该节点的左子节点范围内,先计算左子节点的最右边被毁灭的村庄是否大于k(左子节点的r-rl),如果大于k,那么下一步只执行左子节点继续查询,小于k,就都执行左子节点和右子节点进行查询,直到区间的len等于区间的范围
#include<stdio.h>
#define max(x,y) x>y?x:y
struct node
{
int ll,rl,len;
}a[1000001];
int s[100000];
void build(int l,int r,int i)
{
a[i].ll=a[i].rl=a[i].len=r-l+1;//初始化线段树
if(l==r)
return;
int m=(l+r)/2;
build(l,m,i*2);
build(m+1,r,i*2+1);
}
void update(int l,int r,int i,int pos,int key)
{
if(l==r)
{
a[i].len=a[i].ll=a[i].rl=key;
return;
}
int m=(l+r)/2;
if(m>=pos)
update(l,m,i*2,pos,key);
else
update(m+1,r,i*2+1,pos,key);
a[i].len=max(a[i*2].len,a[i*2+1].len);
a[i].len=max(a[i].len,a[i*2].rl+a[i*2+1].ll);
a[i].ll=a[i*2].ll;
a[i].rl=a[i*2+1].rl;
if(a[i*2].ll==m-l+1)
a[i].ll+=a[i*2+1].ll;
if(a[i*2+1].rl==r-m)
a[i].rl+=a[i*2].rl;
}
int query(int l,int r,int i,int pos)
{
if(a[i].len==0||l==r||a[i].len==r-l+1)
return a[i].len;
int m=(l+r)/2;
if(m>=pos)
{
if(m-a[i*2].rl<pos)
return query(l,m,i*2,pos)+query(m+1,r,i*2+1,m+1);
else
return query(l,m,i*2,pos);
}
else
{
if(m+1+a[i*2+1].ll>pos)
return query(l,m,i*2,m)+query(m+1,r,i*2+1,pos);
else
return query(m+1,r,i*2+1,pos);
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int i,t,top=0;
char ch[2];
build(1,n,1);
while(m--)
{
scanf("%s",ch);
if(ch[0]=='D')
{
scanf("%d",&t);
s[top++]=t;
update(1,n,1,t,0);
}
else if(ch[0]=='R')
{
t=s[--top];
update(1,n,1,t,1);
}
else
{
scanf("%d",&t);
printf("%d\n",query(1,n,1,t));
}
}
}
}