题目大意,给n个点表示n个村庄,一开始都是相连的,现在有3种操作:Q x,查询第与第x个村庄相连的村庄个数;D x,摧毁掉第x个村庄;R 恢复刚摧毁的村庄。
题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄,这里提供2种方法:
1。自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。
2。自底向上找,我们建立线段树的时候把每个叶子节点即每个村庄的位置找到,然后分别从x-1和x+1的位置往两边找,也是找到第一个不存在的村庄为止。
本来比较看好第二种方法,实际提交了一下,第一种效率貌似高一点。
详情请见代码:
自顶向下:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 50005;
int stack[N],top;
int n,m;
int tree[N<<2];
char op[3];
int leaf[N];
void build(int num,int s,int e)
{
if(s == e)
{
tree[num] = 1;
leaf[s] = num;
return;
}
int mid = (s + e)>>1;
build(num<<1,s,mid);
build(num<<1|1,mid + 1,e);
tree[num] = tree[num<<1] + tree[num<<1|1];
}
void insert(int num,int s,int e,int pos,int val)
{
if(s == e)
{
tree[num] = val;
return;
}
int mid = (s + e)>>1;
if(pos <= mid)
insert(num<<1,s,mid,pos,val);
else
insert(num<<1|1,mid + 1,e,pos,val);
if(tree[num<<1] == mid - s + 1 && tree[num<<1|1] == e - mid)
tree[num] = e - s + 1;
else
tree[num] = 0;
}
int query(int num,int s,int e,int pos,int dir)
{
if(pos > n || pos < 1)
return pos;
if(tree[num] == e - s + 1)
{
if(dir)//->
return query(1,1,n,e + 1,dir);//重新从e+1开始往右找
else
return query(1,1,n,s - 1,dir);
}
if(s == e)
return s;
int mid = (s + e)>>1;
if(pos <= mid)
return query(num<<1,s,mid,pos,dir);
else
return query(num<<1|1,mid + 1,e,pos,dir);
}
void print(int num,int s,int e)
{
for(int i = 1;i <= n;i ++)
printf("%d ",tree[leaf[i]]);
}
int main()
{
int x;
int cnt;
while(scanf("%d%d",&n,&m) != EOF)
{
build(1,1,n);
top = 0;
while(m --)
{
scanf("%s",op);
if(op[0] == 'R')
{
insert(1,1,n,stack[--top],1);
}
else
{
scanf("%d",&x);
if(op[0] == 'D')
{
insert(1,1,n,x,0);
stack[top ++] = x;
}
else
{
int ans = tree[leaf[x]];
if(ans == 0)
printf("0\n");
else
{
ans = 1;
if(x < n)
{
cnt = query(1,1,n,x + 1,1);//右
ans += (cnt - x - 1);
}
//printf("cnt:%d\n",cnt);
if(x > 1)
{
cnt = query(1,1,n,x - 1,0);//左
ans += (x - cnt - 1);
}
//printf("cnt:%d\n",cnt);
printf("%d\n",ans);
}
}
}
}
}
return 0;
}
//hdu546MS 1008K
//poj1036K 266MS
自底向上找:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 50005;
int stack[N],top;
int n,m;
struct node
{
int l,r,len;
}tree[N<<2];
char op[3];
int leaf[N];
void build(int num,int s,int e)
{
if(s == e)
{
tree[num].len = 1;
tree[num].l = tree[num].r = s;
leaf[s] = num;
return;
}
int mid = (s + e)>>1;
build(num<<1,s,mid);
build(num<<1|1,mid + 1,e);
tree[num].len = tree[num<<1].len + tree[num<<1|1].len;
tree[num].l = s;
tree[num].r = e;
}
void insert(int num,int pos,int val)
{
if(tree[num].l == tree[num].r)
{
tree[num].len = val;
return;
}
int mid = (tree[num].l + tree[num].r)>>1;
if(pos <= mid)
insert(num<<1,pos,val);
else
insert(num<<1|1,pos,val);
if(tree[num<<1].len == mid - tree[num].l + 1 && tree[num<<1|1].len == tree[num].r - mid)
tree[num].len = tree[num].r - tree[num].l + 1;
else
tree[num].len = 0;
}
void print()
{
int i;
for(i = 1;i <= n;i ++)
printf("%d ",tree[leaf[i]].len);
putchar(10);
}
int main()
{
int x;
int cnt;
while(scanf("%d%d",&n,&m) != EOF)
{
build(1,1,n);
top = 0;
while(m --)
{
scanf("%s",op);
if(op[0] == 'R')
{
insert(1,stack[--top],1);
}
else
{
scanf("%d",&x);
if(op[0] == 'D')
{
insert(1,x,0);
stack[top ++] = x;
}
else
{
int ans = tree[leaf[x]].len;
if(ans == 0)
printf("0\n");
else
{
int tl,tr;
tl = x - 1;//记录x左边第一个断点
tr = x + 1;//记录x右边第一个断点
int tmp;
while(tl >= 1 && tree[leaf[tl]].len == 1)
{
tmp = leaf[tl];
if(tmp & 1)//在右子树上,往根找就是往左找
{
while(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1 && tmp > 1)
{
tmp /= 2;
if(!(tmp & 1))//到了左子树上,找到头了
{
break;
}
}
if(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1)//加上这句优化后hdu515MS 2032K
tl = tree[tmp].l - 1;//poj2068K 282MS
else
tl = tree[tmp<<1|1].l - 1;
}
else
tl --;
}
while(tr <= n && tree[leaf[tr]].len == 1)
{
tmp = leaf[tr];
if(tmp & 1)
tr ++;
else
{
while(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1 && tmp > 1)
{
tmp /= 2;
if(tmp & 1)//找到了右子树上面,找到最右边了
break;
}
if(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1)
tr = tree[tmp].r + 1;
else
tr = tree[tmp<<1].r + 1;
}
}
//printf("tl:%d tr:%d\n",tl,tr);
ans = tr - tl - 1;
printf("%d\n",ans);
}
}
}
//print(1,1,n);
//putchar(10);
}
}
return 0;
}
//hdu1031MS 2032K
//poj2068K 391MS