题意:给你n连成一条线的点,m个操作。D x把第x个村庄破坏,Q x查询与第x个村庄直接和间接相连的村庄数目(包括它自己),R把最早破坏的一个村庄恢复。
除了下面的另一种方法外,现在再做的时候,想到了另一种方法,在查询的时候,更新查找到的范围的左右端点。
/*代码风格更新后*/ #include <iostream> #include <cstdio> #include <cstring> #include <stack> using namespace std; #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1)) const int N=50005; struct node { int lft,rht; int lmx,rmx; int len(){return rht-lft+1;} int mid(){return MID(lft,rht);} void init(){lmx=rmx=len();} void fun(int valu) { if(valu==-1) lmx=rmx=0; else lmx=rmx=1; } }; int n,m; struct Segtree { node tree[N*4]; void up(int ind) { tree[ind].lmx=tree[LL(ind)].lmx; tree[ind].rmx=tree[RR(ind)].rmx; if(tree[LL(ind)].lmx==tree[LL(ind)].len()) tree[ind].lmx+=tree[RR(ind)].lmx; if(tree[RR(ind)].rmx==tree[RR(ind)].len()) tree[ind].rmx+=tree[LL(ind)].rmx; } void build(int lft,int rht,int ind) { tree[ind].lft=lft,tree[ind].rht=rht; tree[ind].init(); if(lft!=rht) { int mid=tree[ind].mid(); build(lft,mid,LL(ind)); build(mid+1,rht,RR(ind)); } } void updata(int pos,int ind,int valu) { if(tree[ind].lft==tree[ind].rht) tree[ind].fun(valu); else { int mid=tree[ind].mid(); if(pos<=mid) updata(pos,LL(ind),valu); else updata(pos,RR(ind),valu); up(ind); } } void query(int pos,int ind,int& x,int& y) { if(tree[ind].lft==tree[ind].rht) { if(tree[ind].lmx==1) x=y=tree[ind].lft; else x=y=0; } else { int mid=tree[ind].mid(); if(pos<=mid) query(pos,LL(ind),x,y); else query(pos,RR(ind),x,y); if(tree[LL(ind)].rht==y) y+=tree[RR(ind)].lmx; if(tree[RR(ind)].lft==x) x-=tree[LL(ind)].rmx; } } }seg; int main() { while(scanf("%d%d",&n,&m)!=EOF) { stack<int> q; seg.build(1,n,1); while(m--) { char cmd[5]; int pos,st,ed; scanf("%s",cmd); if(cmd[0]=='D') { scanf("%d",&pos); seg.updata(pos,1,-1); q.push(pos); } else if(cmd[0]=='Q') { scanf("%d",&pos); seg.query(pos,1,st,ed); if(st==0&&ed==0) puts("0"); else printf("%d\n",ed-st+1); //cout<<st<<" "<<ed<<endl; } else { seg.updata(q.top(),1,1); q.pop(); } } } return 0; }
题目没有说有多组数据,不过却有多组数据,晕死。和hotel那题比较相似,在查询的时候要注意,要先查询是否在父区间的左端点的和右端点连续的范围内,然后查询是否在左右子区间的连接处。而不是查询是否在左子区间的左端点的连续的范围内,这样会出现错误。因为有一种情况是父区间的连续范围超过了中点。
/*代码风格更新前*/ #include <iostream> #include <cstdio> #include <stack> using namespace std; const int N=50005; struct node { int left,right; int lmax,rmax; int mid(){return left+(right-left)/2;} int dis(){return right-left+1;} }; struct Segtree { node tree[N*4]; void build(int left,int right,int r) { tree[r].left=left; tree[r].right=right; tree[r].lmax=tree[r].rmax=tree[r].dis(); if(left<right) { int mid=tree[r].mid(); build(left,mid,r*2); build(mid+1,right,r*2+1); } } void updata(int pos,int r,int co) { if(tree[r].left==tree[r].right) tree[r].lmax=tree[r].rmax=co; else { int mid=tree[r].mid(); if(pos<=mid) updata(pos,r*2,co); else if(pos>mid) updata(pos,r*2+1,co); tree[r].lmax=tree[r*2].lmax; tree[r].rmax=tree[r*2+1].rmax; if(tree[r*2].lmax==tree[r*2].dis()) tree[r].lmax+=tree[r*2+1].lmax; if(tree[r*2+1].rmax==tree[r*2+1].dis()) tree[r].rmax+=tree[r*2].rmax; } } int query(int pos,int r) { if(tree[r].left==tree[r].right) return tree[r].lmax; else { int mid=tree[r].mid(); if(tree[r].lmax+tree[r].left>pos) return tree[r].lmax; else if(tree[r*2+1].lmax+tree[r*2+1].left>pos&&tree[r*2].right-tree[r*2].rmax<pos) return tree[r*2].rmax+tree[r*2+1].lmax; else if(tree[r].right-tree[r].rmax<pos) return tree[r].rmax; else if(pos<=mid) return query(pos,r*2); else return query(pos,r*2+1); } } }seg; int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { stack<int> q; seg.build(1,n,1); for(int i=0;i<m;i++) { int a; char cmd[5]; scanf("%s",cmd); if(cmd[0]=='D') { scanf("%d",&a); seg.updata(a,1,0); q.push(a); } else if(cmd[0]=='Q') { scanf("%d",&a); printf("%d\n",seg.query(a,1)); } else { seg.updata(q.top(),1,1); q.pop(); } } } return 0; }