小记:平衡树或者线段树都可以
思路:
1,、平衡树解法:
因为是从小到大排序好的,所以可以用到平衡树来解。
每碰到一个要销毁的,就插入到平衡树,最开始插入一个0,和n+1,两个值,为了求解用的,
这样我们可以知道,在平衡树里,是一个销毁的顺序表,例如 0 1 3 5 9 12 n=11
那么当我们要查6时,我们用lowerbound()方法可以求得在set里第一个大于等于6的位置是哪个,很明显是9
那么我们再将其往回退一个,也就是求得最后一个小于等于6的位置,那个位置的值是5,那么6的连续区间存活的村庄个数就是9-5-1 = 3 (左右两端都不包括,所以-1)
细心的读者会发现,等于的情况就是我们要查的村庄被摧毁了。上面说的回退其实并不正确,因为当返回的就是等于的位置时,那么我们就不必回退了,这个一个if判断一下就OK
2、线段树解法:
定义一个结构体:
包含区间[l,r]
当前区间左端点往右最长的连续段长度ll, 以及右端点的rl, 和当前区间最长的连续段长度ml
关键在更新查询两个操作, 注意边界问题
[a, b] - 节点i
[a, c] - 节点i<<1 [c+1, b] - 节点(i<<1)|1
最大连续段的更新:a[i].ml = max(a[i<<1].ml, a[(i<<1)|1].ml), a[i].ml = max(a[i].ml, a[i<<1].rl + a[(i<<1)|1].ll);
左连续段的更新:a[i].ll=a[i<<1].ll;if(a[i<<1].ll==a[i<<1].r-a[i<<1].l+1)a[i].ll+=a[(i<<1)|1].ll;
右连续段的更新:a[i].rl=a[(i<<1)|1].rl;if(a[(i<<1)|1].rl==a[(i<<1)|1].r-a[(i<<1)|1].l+1)a[i].rl+=a[i<<1].rl;
查询:
如果再当前区间的左儿子的右边连续段内:query(i<<1,t)+query((i<<1)|1,mid+1); 否则:query(i<<1,t);
相反在当前区间的右儿子的左连续段内:query((i<<1)|1,t)+query(i<<1,mid);否则:query((i<<1)|1,t);
1、平衡树代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define eps 10e-8 const int MAX_ = 10010; const int N = 100010; const int INF = 0x7fffffff; int main(){ int n, m, x; char c; set<int>st; set<int>::iterator it; while(~scanf("%d%d", &n, &m)){ stack<int>s; st.clear(); st.insert(0); st.insert(n+1); for(int i = 0; i < m; ++i){ getchar(); scanf("%c",&c); if(c != 'R')scanf("%d", &x); else { int x = s.top();s.pop(); it = st.lower_bound(x); st.erase(it);continue; } if(c == 'D'){ s.push(x); st.insert(x); } else { it = st.lower_bound(x); if(*it > x)--it; if(*it == x){ puts("0"); } else { int l,r; l = *it++;r = *it; printf("%d\n",r-l-1); } } } } return 0; }
2、线段树代码:
#include<iostream> #include <stdio.h> using namespace std; const int maxn = 50010; int Q[maxn]; int stack[maxn]; bool isok[maxn]; //seg tree struct node { int l,r; int ml; //最大长度,方便下面计算而已//以上3个值均不变 int ll,rl; //分别表示从左节点开始的长度,从右节点开始的长度 }; node tree[maxn*3]; void maketree(int a,int b,int k) { tree[k].l = a; tree[k].r = b; tree[k].ml = b-a+1; tree[k].ll = b-a+1; tree[k].rl = b-a+1; if(a == b) return; int mid = (a+b)>>1; maketree(a,mid,k<<1); maketree(mid+1,b,(k<<1)|1); } void update(int p,int i,int val) { if(tree[i].l == tree[i].r) { if(!val) { tree[i].ll = 0; tree[i].rl = 0; tree[i].ml = 0; isok[p] = 0; //del } else { tree[i].ll = 1; tree[i].rl = 1; tree[i].ml = 1; isok[p] = 1;//rebuild } return; } int mid = (tree[i].l + tree[i].r)>>1; if(p <= mid) update(p,i<<1,val); else update(p,(i<<1)|1,val); tree[i].ll=tree[i<<1].ll; tree[i].rl=tree[(i<<1)|1].rl; tree[i].ml=max(tree[i<<1].ml,tree[(i<<1)|1].ml); tree[i].ml=max(tree[i].ml,tree[i<<1].rl+tree[(i<<1)|1].ll); if(tree[i<<1].ll==tree[i<<1].r-tree[i<<1].l+1) tree[i].ll+=tree[(i<<1)|1].ll; if(tree[(i<<1)|1].rl==tree[(i<<1)|1].r-tree[(i<<1)|1].l+1) tree[i].rl+=tree[i<<1].rl; } int query(int i,int t) { if(tree[i].l == tree[i].r || tree[i].ml==0 ||tree[i].ml==tree[i].r-tree[i].l+1) { return tree[i].ml; } int mid=(tree[i].l+tree[i].r)>>1; if(t<=mid) { if(t >= tree[i<<1].r - tree[i<<1].rl+1) return query(i<<1,t)+query((i<<1)|1,mid+1); else return query(i<<1,t); } else { if(t<=tree[(i<<1)|1].l+tree[(i<<1)|1].ll-1) return query((i<<1)|1,t)+query(i<<1,mid); else return query((i<<1)|1,t); } } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { //init for(int i=1; i<=n; i++) isok[i] = 1; maketree(1,n,1); char s[2]; int top = 0; int pos; for(int i=1; i<=m; i++) { scanf("%s",s); if(s[0] == 'D') { scanf("%d",&pos); stack[++top] = pos; if(isok[pos]) //当结点还完好,才要破坏它 update(pos,1,0); } else if(s[0] == 'Q') { scanf("%d",&pos); if(isok[pos] == 0) //如果pos位置已损坏..直接输出0 printf("0\n"); else printf("%d\n",query(1,pos)); } else { if( top == 0) continue; update(stack[top--],1,1); } } } return 0; }