->题目请戳这 和这->
题目大意,给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