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!
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!
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.
7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
1 0 2 4
和上一题比较相似,上一题还难些。记录s,ls,rs,当前区间的最大连续的村子的个数、区间左起连续的村子,区间右起连续的区间
注释挺多的
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 50100
struct node
{
int l,r,ls,rs,s;//区间左右端点,左右端点连续的最大长度,区间内最大连续的长度
}tree[maxn<<2];
int re[maxn];//保存被破坏的点
void build(int l,int r,int node)
{
tree[node].l=l;tree[node].r=r;//一开始所以的点都是好的
tree[node].ls=tree[node].rs=tree[node].s=r-l+1;
if(r==l)
return ;
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
}
void pushup(int node)
{
tree[node].ls=tree[node<<1].ls;//左右区间的端点连续长度,分别大于等于,左右子区间的左右端点连续的区间长度
tree[node].rs=tree[node<<1|1].rs;
if(tree[node<<1].ls==tree[node<<1].r-tree[node<<1].l+1)//这里是加上大于的那一部分
tree[node].ls+=tree[node<<1|1].ls;
if(tree[node<<1|1].rs==tree[node<<1|1].r-tree[node<<1|1].l+1)
tree[node].rs+=tree[node<<1].rs;
//当前区间的最大连续长度=max{左子区间的最大长度,右子区间的最大长度,左子区间的右边边加上右子区间的左边}
tree[node].s=max(tree[node<<1].s,max(tree[node<<1|1].s,tree[node<<1].rs+tree[node<<1|1].ls));
}
int cal(int t,int node)
{
int l=tree[node].l,r=tree[node].r;
//到达了叶子或该区间所以的点都毁了或该区间的点都是好的,则直接返回s
if(l==r||tree[node].s==0||tree[node].s==r-l+1)
return tree[node].s;
int mid=(l+r)>>1;
if(t<=mid)
{
if(t>=tree[node<<1].r-tree[node<<1].rs+1)//t在左子区间右端连续区域内,则可能连续到右子区间中去
{
return cal(t,node<<1)+cal(mid+1,node<<1|1);//同理,注意条件,等式右为边界条件
}
else
return cal(t,node<<1);
}
else
{
if(t<=tree[node<<1|1].l+tree[node<<1|1].ls-1)//同理
return cal(t,node<<1|1)+cal(mid,node<<1);
else
return cal(t,node<<1|1);
}
}
void update(int t,int c,int node)
{
int l=tree[node].l,r=tree[node].r;
if(l==r)//到达叶子,即需更新的点
{
tree[node].s=tree[node].ls=tree[node].rs=c;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)
update(t,c,node<<1);
else
update(t,c,node<<1|1);
pushup(node);//更新祖宗
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
char ss[2];
int x;
build(1,n,1);
int top=0;
while(m--)
{
scanf("%s",ss);
if(ss[0]=='R')
{
x=re[--top];
update(x,1,1);
}
else
{
scanf("%d",&x);
if(ss[0]=='Q')
{
printf("%d\n",cal(x,1));
}
else
{
re[top++]=x;
update(x,0,1);
}
}
//for(int i=1;i<=n*4;i++)
// printf("%d %d %d %d\n",i,tree[i].s,tree[i].l,tree[i].r);
}
}
return 0;
}