7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
1 0 2 4
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1540
题意:有n个村庄,现在,每次摧毁一个村庄或修好一个村庄,或者问你和这个村庄连接的村庄个数。。。
分析:这题相比上题来讲,就是个超精简版吧,只要记录每个区间左边开始的连续村庄数,和右边开始的连续村庄数,每次摧毁或维修都是单点更新,而查找一个点,只要这个点,在 m-lmost[lson]+1~m+rmost[rson]之间,就说明它被这个区间的两个子区间包含了,直接返回就行,否则就是只被一个区间包含,继续递归。。。
代码:
#include<cstdio> #include<iostream> #define ls rt<<1 #define rs rt<<1|1 #define lson l,m,ls #define rson m+1,r,rs #define uprt rt,m-l+1,r-m using namespace std; const int mm=55555; const int mn=mm<<2; int lm[mn],rm[mn]; int q[mm]; void pushup(int rt,int l1,int l2) { lm[rt]=lm[ls],rm[rt]=rm[rs]; if(lm[rt]>=l1)lm[rt]+=lm[rs]; if(rm[rt]>=l2)rm[rt]+=rm[ls]; } void build(int l,int r,int rt) { lm[rt]=rm[rt]=r-l+1; if(l==r)return; int m=(l+r)>>1; build(lson); build(rson); } void updata(int p,int x,int l,int r,int rt) { if(l==r) { lm[rt]=rm[rt]=x; return; } int m=(l+r)>>1; if(p<=m)updata(p,x,lson); else updata(p,x,rson); pushup(uprt); } int query(int p,int l,int r,int rt) { if(l==r)return 0; int m=(l+r)>>1; if(m-rm[ls]+1<=p&&m+lm[rs]>=p)return rm[ls]+lm[rs]; if(p<=m)return query(p,lson); return query(p,rson); } int main() { int i,n,m,top; char op[55]; while(~scanf("%d%d",&n,&m)) { build(1,n,1); top=0; while(m--) { scanf("%s",op); if(op[0]=='R') { if(top)updata(q[top--],1,1,n,1); } else scanf("%d",&i); if(op[0]=='D') { q[++top]=i; updata(i,0,1,n,1); } if(op[0]=='Q')printf("%d\n",query(i,1,n,1)); } } return 0; }