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;
}
解决这道题,说下思路,(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;
}
相关文章推荐
- HDU 1540 区间合并线段树
- HDU 1540 POJ 2892 线段树区间合并
- Hdu 1540 【线段树--区间合并】.cpp
- hdu 1540 线段树区间合并
- hdu1540之线段树单点更新+区间合并
- hdu 1540 Tunnel Warfare(线段树区间合并)
- HDU 1540 Tunnel Warfare (线段树区间合并)
- HDU - 1540 Tunnel Warfare(线段树 区间合并)
- hdu 1540 线段树区间合并
- hdu1540 Tunnel Warfare 线段树区间合并
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- HDU-1540 Tunnel Warfare 线段树 区间合并
- hdu 1540 Tunnel Warfare 线段树--区间合并
- hdu 1540(线段树单点更新 区间合并)
- HDU 1540 && POJ 2892 Tunnel Warfare (线段树,区间合并).
- HDU 1540 Tunnel Warfare(线段树单点更新+区间合并)
- HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)
- hdu 1540 线段树+区间合并
- hdu 1540 Tunnel Warfare(线段树单点更新+区间合并)
- HDU 1540 Tunnel Warfare(线段树 区间合并 +单点更新)