题目大意是:
给你n个房子,然后有m个操作:
(1):D x:代表摧毁第x个村庄
(2):Q x:查询与第x个村庄直接或间接(即为通过其他没有被炸毁的村庄相连接的)的村子的个数
(3):R :代表的是最后被摧毁的那个村庄被修复(这里就要用到栈了,哈哈)
唔。。。这道线段树的题目想了很久也没啥思路,网上说和poj hotel的那题很像,但是一直联系不起来,但是想通了也就这样吧。
其实线段树是一个很灵活的东西,它是辅助功能,这里它的作用是为了query(查询操作)与update(更新操作)。
当然其中还有一个lazy-tag的思想,那就是向上更新的时候,这个是经典的区间合并的操作,(其实我觉得叫这名字有点怪怪的感觉。。。
void pushup(int v){
int temp=v<<1;
tree[v].ls=tree[temp].ls;
tree[v].rs=tree[temp+1].rs;
if(tree[v].ls==tree[temp].r-tree[temp].l+1) tree[v].ls+=tree[temp+1].ls;
if(tree[v].rs==tree[temp+1].r-tree[temp+1].l+1) tree[v].rs+=tree[temp].rs;
tree[v].ms=max(tree[temp].rs+tree[temp+1].ls,max(tree[temp].ms,tree[temp+1].ms));
}
首先讲讲更新操作,这里我们是把它更新到子节点,然后利用lazy思想在往上更新。
void update(int pos,int v,int cnt){
if(tree[v].l==tree[v].r&&tree[v].l==pos){
if(cnt==0) tree[v].ls=tree[v].rs=tree[v].ms=0;
else tree[v].ls=tree[v].rs=tree[v].ms=1;
return;
}
int mid=(tree[v].l+tree[v].r)>>1;
int temp=v<<1;
if(pos<=mid) update(pos,temp,cnt);
else update(pos,temp+1,cnt);
pushup(v);
}
最重要的要数查找了吧(query)。
首先我们知道如果一个节点如果它满足当前节点是满的或是它是全空的,或是它是子节点,那么我们就返回当前节点的ms值(代表的是这个区间中的最大连续区间个数),如果不是,我们要分两种情况:
(1)首先当前节点是在左儿子的地方,如果pos这个我们要求的点是在左儿子的右区间内的话,那么我们还要再去判断一下是不是在右儿子上也有一段区间与左儿子相连,这也就是为什么要query(pos,temp)+query(pos,temp+1),后面的那个的目的就是为了查询判断一下在右儿子中是否还有一段连续的区间使得也刚好与左儿子相连 。
(2)讨论当前节点是在右儿子的地方,思路也是同样的。
如图中画黄线的所示:如果我们要查询2,那么我们还要判断右儿子上还有没有连起来的区间。
int query(int pos,int v){
if(tree[v].ms==0||tree[v].ms==tree[v].r-tree[v].l+1||tree[v].l==tree[v].r){
return tree[v].ms;
}
int temp=v<<1;
int mid=(tree[v].l+tree[v].r)>>1;
if(pos<=mid){
if(pos>=tree[temp].r-tree[temp].rs+1) return query(pos,temp)+query(mid+1,temp+1);
else return query(pos,temp);
}
else{
if(pos<=tree[temp+1].l+tree[temp+1].ls-1) return query(mid,temp)+query(pos,temp+1);
else return query(pos,temp+1);
}
}
总之挺不错的一道线段树的题目,一开始我一直不知道要怎么把线段树给用上去。。。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
stack<int> sk;
#define maxn 55555
struct node{
int l,r;
int ls,rs,ms;
}tree[maxn*4];
void pushup(int v){
int temp=v<<1;
tree[v].ls=tree[temp].ls;
tree[v].rs=tree[temp+1].rs;
if(tree[v].ls==tree[temp].r-tree[temp].l+1) tree[v].ls+=tree[temp+1].ls;
if(tree[v].rs==tree[temp+1].r-tree[temp+1].l+1) tree[v].rs+=tree[temp].rs;
tree[v].ms=max(tree[temp].rs+tree[temp+1].ls,max(tree[temp].ms,tree[temp+1].ms));
}
void build(int l,int r,int v){
tree[v].l=l;
tree[v].r=r;
tree[v].ls=tree[v].rs=tree[v].ms=r-l+1;
if(l==r) return;
int mid=(l+r)>>1;
int temp=v<<1;
build(l,mid,temp);
build(mid+1,r,temp+1);
}
int query(int pos,int v){
if(tree[v].ms==0||tree[v].ms==tree[v].r-tree[v].l+1||tree[v].l==tree[v].r){
return tree[v].ms;
}
int temp=v<<1;
int mid=(tree[v].l+tree[v].r)>>1;
if(pos<=mid){
if(pos>=tree[temp].r-tree[temp].rs+1) return query(pos,temp)+query(mid+1,temp+1);
else return query(pos,temp);
}
else{
if(pos<=tree[temp+1].l+tree[temp+1].ls-1) return query(mid,temp)+query(pos,temp+1);
else return query(pos,temp+1);
}
}
void update(int pos,int v,int cnt){
if(tree[v].l==tree[v].r&&tree[v].l==pos){
if(cnt==0) tree[v].ls=tree[v].rs=tree[v].ms=0;
else tree[v].ls=tree[v].rs=tree[v].ms=1;
return;
}
int mid=(tree[v].l+tree[v].r)>>1;
int temp=v<<1;
if(pos<=mid) update(pos,temp,cnt);
else update(pos,temp+1,cnt);
pushup(v);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
build(1,n,1);
while(!sk.empty()){
sk.pop();
}
char a[5];
int x;
while(m--){
scanf("%s",a);
if(a[0]=='D'){
scanf("%d",&x);
sk.push(x);
update(x,1,0);
}
else if(a[0]=='Q'){
scanf("%d",&x);
printf("%d\n",query(x,1));
}
else{
x=sk.top();
sk.pop();
update(x,1,1);
}
}
}
加油,wish everyone can achieve their dream!【Acmer ,fighting~ ∶)