小记:平衡树或者线段树都可以
思路:
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;
}