hdu 3308 LCIS 最大连续递增字串长 线段树区间合并
2012-08-03 19:11
351 查看
这是我做的第二个线段树区间合并的问题,之前那个hotel还是借助大神的报告来写的,这个总算是独立自主的完成
这个问题是单点更新,所以不用写push_down,延迟标记……
一个状态记录的是
struct point
{
int l,r,lmax,lmin,rmax,rmin,max;
}p[MAX<<2];l:区间最左边开始的最大连续递增字串长
r:区间最右边开始的最大连续递增字串长
lmin:左子串的第一个数字
lmax:左子串的第后个数字
rmin,rmax是右子串的
max是区间中最长的连续递增字串长
push_up函数中,即父亲的信息,他的最左边开始的最大连续递增字串长为:
如果左儿子区间整个区间递增,并且lmax<右儿子区间的lmin,那么父亲的最大连续递增字串长 左儿子的l加上右儿子的l
否则就是左儿子的l
对父亲的r同理
当然lmax,lmin,rmax,rmin得根据情况更新
父亲的max则是两儿子的最大值与左儿子的r+右儿子的l这三个值中的最大值,这个是容易想象的
本题的update函数没有什么难点
查询函数稍微有点变化,看代码就可知
以下是代码:
#include <cstdio>
#include <cstring>
const int MAX = 100010;
struct point
{
int l,r,lmax,lmin,rmax,rmin,max;
}p[MAX<<2];
int max(int a,int b)
{
return (a>b)?a:b;
}
int min(int a,int b)
{
return (a<b)?a:b;
}
void push_up(int l,int r,int rt)
{
int mid = r+l>>1;
p[rt].l = p[rt<<1].l;
p[rt].lmin = p[rt<<1].lmin;
p[rt].lmax = p[rt<<1].lmax;
p[rt].r = p[rt<<1|1].r;
p[rt].rmin = p[rt<<1|1].rmin;
p[rt].rmax = p[rt<<1|1].rmax;
if(p[rt].l==mid-l+1&&p[rt].lmax<p[rt<<1|1].lmin)
{
p[rt].l+= p[rt<<1|1].l;
p[rt].lmax = p[rt<<1|1].lmax;
}
if(p[rt].r==r-mid&&p[rt].rmin>p[rt<<1].rmax)
{
p[rt].r+= p[rt<<1].r;
p[rt].rmin = p[rt<<1].rmin;
}
int tmp = 0;
if(p[rt<<1].rmax<p[rt<<1|1].lmin)
tmp = p[rt<<1].r+p[rt<<1|1].l;
p[rt].max = max(max(p[rt<<1].max,p[rt<<1|1].max),tmp);
}
void build(int l,int r,int rt)
{
if(l==r)
{
p[rt].l = p[rt].r = p[rt].max = 1;
scanf("%d",&p[rt].lmax);
p[rt].lmin = p[rt].lmax;
p[rt].rmin = p[rt].lmax;
p[rt].rmax = p[rt].lmax;
return;
}
int mid = r+l>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(l,r,rt);
}
void update(int a,int b,int l,int r,int rt)
{
if(l==r)
{
//p[rt].l = p[rt].r = p[rt].max = 1;
p[rt].lmax = b;
p[rt].lmin = p[rt].lmax;
p[rt].rmin = p[rt].lmax;
p[rt].rmax = p[rt].lmax;
return;
}
int mid = l+r>>1;
if(a<=mid) update(a,b,l,mid,rt<<1);
else update(a,b,mid+1,r,rt<<1|1);
push_up(l,r,rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
return p[rt].max;
int mid = r+l>>1;
if(R<=mid) return query(L,R,l,mid,rt<<1);
if(L>mid) return query(L,R,mid+1,r,rt<<1|1);
int tmp = 0;
if(p[rt<<1].rmax<p[rt<<1|1].lmin)
{
int l0 = max(L,mid-p[rt<<1].r+1);
int r0 = min(R,mid+p[rt<<1|1].l);
tmp = r0-l0+1;
}
return max(tmp,max(query(L,R,l,mid,rt<<1),query(L,R,mid+1,r,rt<<1|1)));
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
int n,m,x,y;
scanf("%d%d",&n,&m);
build(0,n-1,1);
char c;
while(m--)
{
scanf(" %c%d%d",&c,&x,&y);
if(c=='Q')
printf("%d\n",query(x,y,0,n-1,1));
else update(x,y,0,n-1,1);
}
}
return 0;
}
这个问题是单点更新,所以不用写push_down,延迟标记……
一个状态记录的是
struct point
{
int l,r,lmax,lmin,rmax,rmin,max;
}p[MAX<<2];l:区间最左边开始的最大连续递增字串长
r:区间最右边开始的最大连续递增字串长
lmin:左子串的第一个数字
lmax:左子串的第后个数字
rmin,rmax是右子串的
max是区间中最长的连续递增字串长
push_up函数中,即父亲的信息,他的最左边开始的最大连续递增字串长为:
如果左儿子区间整个区间递增,并且lmax<右儿子区间的lmin,那么父亲的最大连续递增字串长 左儿子的l加上右儿子的l
否则就是左儿子的l
对父亲的r同理
当然lmax,lmin,rmax,rmin得根据情况更新
父亲的max则是两儿子的最大值与左儿子的r+右儿子的l这三个值中的最大值,这个是容易想象的
本题的update函数没有什么难点
查询函数稍微有点变化,看代码就可知
以下是代码:
#include <cstdio>
#include <cstring>
const int MAX = 100010;
struct point
{
int l,r,lmax,lmin,rmax,rmin,max;
}p[MAX<<2];
int max(int a,int b)
{
return (a>b)?a:b;
}
int min(int a,int b)
{
return (a<b)?a:b;
}
void push_up(int l,int r,int rt)
{
int mid = r+l>>1;
p[rt].l = p[rt<<1].l;
p[rt].lmin = p[rt<<1].lmin;
p[rt].lmax = p[rt<<1].lmax;
p[rt].r = p[rt<<1|1].r;
p[rt].rmin = p[rt<<1|1].rmin;
p[rt].rmax = p[rt<<1|1].rmax;
if(p[rt].l==mid-l+1&&p[rt].lmax<p[rt<<1|1].lmin)
{
p[rt].l+= p[rt<<1|1].l;
p[rt].lmax = p[rt<<1|1].lmax;
}
if(p[rt].r==r-mid&&p[rt].rmin>p[rt<<1].rmax)
{
p[rt].r+= p[rt<<1].r;
p[rt].rmin = p[rt<<1].rmin;
}
int tmp = 0;
if(p[rt<<1].rmax<p[rt<<1|1].lmin)
tmp = p[rt<<1].r+p[rt<<1|1].l;
p[rt].max = max(max(p[rt<<1].max,p[rt<<1|1].max),tmp);
}
void build(int l,int r,int rt)
{
if(l==r)
{
p[rt].l = p[rt].r = p[rt].max = 1;
scanf("%d",&p[rt].lmax);
p[rt].lmin = p[rt].lmax;
p[rt].rmin = p[rt].lmax;
p[rt].rmax = p[rt].lmax;
return;
}
int mid = r+l>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(l,r,rt);
}
void update(int a,int b,int l,int r,int rt)
{
if(l==r)
{
//p[rt].l = p[rt].r = p[rt].max = 1;
p[rt].lmax = b;
p[rt].lmin = p[rt].lmax;
p[rt].rmin = p[rt].lmax;
p[rt].rmax = p[rt].lmax;
return;
}
int mid = l+r>>1;
if(a<=mid) update(a,b,l,mid,rt<<1);
else update(a,b,mid+1,r,rt<<1|1);
push_up(l,r,rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
return p[rt].max;
int mid = r+l>>1;
if(R<=mid) return query(L,R,l,mid,rt<<1);
if(L>mid) return query(L,R,mid+1,r,rt<<1|1);
int tmp = 0;
if(p[rt<<1].rmax<p[rt<<1|1].lmin)
{
int l0 = max(L,mid-p[rt<<1].r+1);
int r0 = min(R,mid+p[rt<<1|1].l);
tmp = r0-l0+1;
}
return max(tmp,max(query(L,R,l,mid,rt<<1),query(L,R,mid+1,r,rt<<1|1)));
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
int n,m,x,y;
scanf("%d%d",&n,&m);
build(0,n-1,1);
char c;
while(m--)
{
scanf(" %c%d%d",&c,&x,&y);
if(c=='Q')
printf("%d\n",query(x,y,0,n-1,1));
else update(x,y,0,n-1,1);
}
}
return 0;
}
相关文章推荐
- HDU 3308——LCIS(线段树,区间合并,最长连续递增子序列)
- HDU 3308 LCIS(线段树+区间合并+最长递增连续子串)
- 线段树区间合并+最长连续递增子序列——HDU 3308
- HDU 3308 LCIS 最长上升字串(线段树区间合并)
- HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)
- 【HDU - 3308】 LCIS 【线段树+单点更新+区间合并】
- HDU 3308 LCIS(线段树:单点更新,求最大连续子串)
- hdoj 3308 LCIS 【线段树单点更新 + 区间合并】【求解最长递增序列 的长度】
- HDU 3308 LCIS 线段树 区间合并 入门题
- hdu 3308 LCIS(线段树区间合并)
- hdu 3308 LCIS(线段树区间合并)
- HDU 3308 LCIS 最长连续递增序列+数据结构+线段树+单点更新
- HDU 3308 LCIS(线段树区间合并)
- HDU 3308 - LCIS(线段树+区间合并)
- HDU 3308 LCIS (线段树区间合并)
- (简单) HDU 3308 LCIS,线段树+区间合并。
- hdu 3308 LCIS (线段树+单点更新+区间合并)
- HDU 3308 LCIS(线段树单点更新区间合并)
- hdu--3308 LCIS(线段树+区间合并)
- HDU 3308 LCIS(线段树区间合并)