您的位置:首页 > 其它

hdu 1540 线段树区间合并

2014-07-17 16:51 246 查看
线段树区间合并~第一次接触,

解决这道题,说下思路,(1)创建树节点,每个节点要记录左连续个数和右连续个数,同时还要有一个标记量cover,当cover为1时,这个区间内所有点都是好的,当cover为0的时候说明这个区间内有一些点被破坏了;

(2)比如要你找出与 x 直接或者间接相连的点的个数,那么我们可以找出区间为(1,x-1)的节点,那么它的左连续个数可以知道,同理找到区间为(x+1,n)的节点,那么他的右连续个数也可以知道,最后再加上1,因为自己本身也得包含进去。

附上代码:

#include <iostream>

#include <stdio.h>

#include <string.h>

#include <stack>

#define N 55000

using namespace std;

struct node

{

int l,r;

int lenl,lenr,cover;

}st[N*5];

int rec
;

void build(int v,int l,int r)

{

st[v].l=l;

st[v].r=r;

st[v].lenl=st[v].lenr=(r-l+1);

st[v].cover=1;

if(l==r)return;

int mid=(l+r)/2;

build(2*v,l,mid);

build(2*v+1,mid+1,r);

}

void update(int v,int w,int val)

{

if(st[v].l==st[v].r)

{

st[v].lenl=st[v].lenr=val;

st[v].cover=val;

return;

}

if(st[v].cover)

{

st[v*2].cover=st[v].cover;

st[v*2+1].cover=st[v].cover;

st[v].cover=0;

}

int mid=(st[v].l+st[v].r)/2;

if(w<=mid)

update(2*v,w,val);

else if(w>mid)

update(2*v+1,w,val);

st[v].lenl=st[2*v].lenl;

st[v].lenr=st[2*v+1].lenr;

if(st[2*v].cover==1)

st[v].lenl+=st[v*2+1].lenl;

if(st[2*v+1].cover==1)

st[v].lenr+=st[v*2].lenr;

st[v].cover=st[v*2].cover&&st[v*2+1].cover;

}

int lquery(int v,int l,int r)

{

if(st[v].l==l&&st[v].r==r)

{

return st[v].lenl;

}

int mid=(st[v].l+st[v].r)/2;

if(r<=mid)

return lquery(2*v,l,r);

else if(l>mid)

return lquery(2*v+1,l,r);

else

{

int t=lquery(2*v,l,mid);

if(t==mid-l+1)

{

t+=lquery(2*v+1,mid+1,r);

}

return t;

}

}

int rquery(int v,int l,int r)

{

if(st[v].l==l&&st[v].r==r)

{

return st[v].lenr;

}

int mid=(st[v].l+st[v].r)/2;

if(r<=mid)

return rquery(2*v,l,r);

else if(l>mid)

return rquery(2*v+1,l,r);

else

{

int t=rquery(2*v+1,mid+1,r);

if(t==r-mid)

{

t+=rquery(2*v,l,mid);

}

return t;

}

}

int main()

{

int n,m;

while(scanf("%d%d",&n,&m)!=EOF)

{

stack<int>stk;

memset(rec,0,sizeof(rec));

int cnt=0;

char s[10];

build(1,1,n);

for(int i=0;i<m;i++)

{

scanf("%s",s);

if(s[0]=='D')

{

int a;

scanf("%d",&a);

rec[a]=1;

stk.push(a);

update(1,a,0);

}

else if(s[0]=='R')

{

if(!stk.empty())

{

int a=stk.top();

rec[a]=0;

stk.pop();

update(1,a,1);

}

}

else if(s[0]=='Q')

{

int a;

scanf("%d",&a);

if(rec[a])

printf("0\n");

else

{

if(a==1) //我的代码得分三种情况,当询问第一个点的时候,当询问最后一个点的时候,当所询问点在中间的时候,就因为这个地方没注意, // RE了很多次

printf("%d\n",lquery(1,2,n)+1);

else if(a==n)

printf("%d\n",rquery(1,1,n-1)+1);

else

printf("%d\n",lquery(1,a+1,n)+rquery(1,1,a-1)+1);

}

}

}

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: