您的位置:首页 > 其它

HDU 3308 LCSI 【线段树】 与 poj 3667 hotel

2010-02-08 13:03 453 查看
听说这个题目是那套题目里最简单的线段树了。

序列a 4 3 9 7 6 8
下标i 1 2 3 4 5 6
区间结点要记录的三个信息:当前最长递增的序列值,从左端开始的最长序列值,到右端结束的最长序列值。

线段树




代码:
//query 语句最值得细看----多段联合 这个递归从最后开始往前联合。一般都要从后往前比较好。因为最小单位可以确定其值了,当然这里不需要这么考虑。
void query(int p,int l,int r,node &set)
{
if(tree[p].lt==l&&tree[p].rt==r)
{
set = tree[p];
return ;
}

int m = (tree[p].lt+tree[p].rt)>>1;
if(m>=r){query(p*2,l,r,set);}
else if(l>m){query(p*2+1,l,r,set);}
else
{
node t1,t2;
query(p*2,l,m,t1);
query(p*2+1,m+1,r,t2);
set.m = max(t1.m,t2.m);
set.lt = t1.lt;
set.rt= t2.rt;
set.l = t1.l;
set.r = t2.r;

if(a[t1.rt]<a[t2.lt])
{
set.m = max(set.m,(t1.r+t2.l));

if(t1.l==(t1.rt-t1.lt+1))
{
set.l = t1.l+t2.l;
}
if(t2.r ==(t2.rt-t2.lt+1))
{
set.r = t1.r+t2.r;
}
}

}

}


完整代码:
//写的比较丑~~~
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define size 100010

#define max(x,y) (x)>(y)?(x):(y)
typedef struct tree
{
int lt,rt,l,r;
int m;
}node;
node tree[size*3+1];
int a[size];
void build(int p,int l,int r)//建立线段树
{
tree[p].lt=l;
tree[p].rt=r;

if(l==r){
tree[p].l=1;
tree[p].r=1;
tree[p].m=1;

return;}
int m = (l+r)>>1;
build(p*2,l,m);
build(p*2+1,m+1,r);
//	printf("%(1) %d %d  %d %d/n",tree[p*2+1].lt,tree[p*2+1].rt,tree[p*2].m,tree[p*2+1].m);

if(a[tree[p*2].rt]<a[tree[p*2+1].lt])
{	tree[p].m = max((tree[p*2].r+tree[p*2+1].l) , max(tree[p*2].m,tree[p*2+1].m));
if(tree[p*2+1].r==(tree[p*2+1].rt-tree[p*2+1].lt+1))
tree[p].r=tree[p*2].r+tree[p*2+1].r;
else
tree[p].r=tree[p*2+1].r;

if(tree[p*2].l==(tree[p*2].rt-tree[p*2].lt+1))
tree[p].l=tree[p*2].l+tree[p*2+1].l;
else
tree[p].l=tree[p*2].l;

}
else
{
tree[p].m = max(tree[p*2].m,tree[p*2+1].m);
tree[p].l=tree[p*2].l;
tree[p].r=tree[p*2+1].r;
}

}
//query
void query(int p,int l,int r,node &set)
{
if(tree[p].lt==l&&tree[p].rt==r)
{
set = tree[p];
return ;
}

int m = (tree[p].lt+tree[p].rt)>>1;
if(m>=r){query(p*2,l,r,set);}
else if(l>m){query(p*2+1,l,r,set);}
else
{
node t1,t2;
query(p*2,l,m,t1);
query(p*2+1,m+1,r,t2);
set.m = max(t1.m,t2.m);
set.lt = t1.lt;
set.rt= t2.rt;
set.l = t1.l;
set.r = t2.r;

if(a[t1.rt]<a[t2.lt])
{
set.m = max(set.m,(t1.r+t2.l));
if(t1.l==(t1.rt-t1.lt+1))
{
set.l = t1.l+t2.l;
}
if(t2.r ==(t2.rt-t2.lt+1))
{
set.r = t1.r+t2.r;
}
}

}

}

void updata(int p,int l,int r,int ta,int tc)
{
if(l==r&&l==ta&&r==ta)
{
a[ta]=tc;
return ;

}
int m = (l+r)>>1;
if(m>=ta){updata(p*2,l,m,ta,tc);}
else{updata(p*2+1,m+1,r,ta,tc);}

if(a[tree[p*2].rt]<a[tree[p*2+1].lt])
{	tree[p].m = max((tree[p*2].r+tree[p*2+1].l) , max(tree[p*2].m,tree[p*2+1].m));
if(tree[p*2+1].r==(tree[p*2+1].rt-tree[p*2+1].lt+1))
tree[p].r=tree[p*2].r+tree[p*2+1].r;
else
tree[p].r=tree[p*2+1].r;

if(tree[p*2].l==(tree[p*2].rt-tree[p*2].lt+1))
tree[p].l=tree[p*2].l+tree[p*2+1].l;
else
tree[p].l=tree[p*2].l;

}
else
{
tree[p].m = max(tree[p*2].m,tree[p*2+1].m);
tree[p].l=tree[p*2].l;
tree[p].r=tree[p*2+1].r;
}

}

int main()
{
int t,i,n,m,x,y;
char c[2];
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
memset(tree,0,sizeof(tree));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);

build(1,1,n);
//	printf("%d",tree[1].m);
//for(i=1;i<=6*n-1;i++)
//printf("%d %d max = %d/n",tree[1].lt,tree[1].rt,tree[1].m);
while(m--)
{

scanf("%s",c);
if(c[0]=='Q')
{
scanf("%d%d",&x,&y);
y++;x++;
node set;
query(1,x,y,set);
printf("%d/n",set.m);
}else
{
scanf("%d%d",&x,&y);
x++;
updata(1,1,n,x,y);
}
}
}

}
return 0;
}

/*
1
10 10
7 7 3 4 5 9 10 8 1 8

res.lt=l.lt;
res.rt=r.rt;
res.mx=max(l.mx, r.mx);
if(dt[im-1]<dt[im]) {
int len=l.rt+r.lt;
if(l.rt==im-il) res.lt=len;
if(r.lt==ir-im) res.rt=len;
if(len>res.mx) res.mx=len;
}
*/


来看看poj的hotel吧 比较相似。把思想搞懂了就好做了。
看下图希望能够更好理解。



两天的对题目和代码的细细分析,终于搞懂理解了,o(∩_∩)o 哈哈


主要关键是往回来的时候当前结点下面的信息要被当前结点影响。当前结点区间全部被占下层的孩子就是更新。
记住找区间的时候
if(tree[p].l==l&&tree[p].r==r)
否则会去递归到底层,这样就时间并没有优化,线段树也不起作用了。
看代码:
#include<iostream>
using namespace std;
#define max(x,y) ((x)>(y)?(x):(y))
#define size 50010
struct seg {int l,r,llen,rlen,m;};
seg tree[size*4];
int n;

void down(int p)
{
if(tree[p].m==(tree[p].r-tree[p].l+1))
{
tree[p*2].m=tree[p*2].llen=tree[p*2].rlen=(tree[p*2].r-tree[p*2].l+1);
tree[p*2+1].m=tree[p*2+1].llen=tree[p*2+1].rlen=(tree[p*2+1].r-tree[p*2+1].l+1);

}
else if(tree[p].m==0)
{

tree[p*2].m=tree[p*2].llen=tree[p*2].rlen=0;
tree[p*2+1].m=tree[p*2+1].llen=tree[p*2+1].rlen=0;
}
}

void spread(int p) {

int mx = max(tree[p*2].m,tree[p*2+1].m);
if((tree[p*2].r-tree[p*2].l+1)==tree[p*2].llen)
{
tree[p].llen = tree[p*2].llen + tree[p*2+1].llen;
}
else
{
tree[p].llen = tree[p*2].llen;
}
if((tree[p*2+1].r-tree[p*2+1].l+1)==tree[p*2+1].rlen)
{
tree[p].rlen = tree[p*2].rlen + tree[p*2+1].rlen;
}
else
{
tree[p].rlen = tree[p*2+1].rlen;
}
tree[p].m = max(mx,(tree[p*2].rlen+tree[p*2+1].llen));

}

//check
void build(int p,int l,int r)
{
tree[p].l=l;tree[p].r=r;
tree[p].llen=tree[p].rlen=tree[p].m=tree[p].r-tree[p].l+1;
if(l==r)
{

tree[p].m=1;
tree[p].llen=1;
tree[p].rlen=1;
return ;
}
int m = (l+r)>>1;

build(p*2,l,m);
build(p*2+1,m+1,r);

}

void ins(int p,int l,int r)
{

if(tree[p].l==l&&tree[p].r==r)
{
tree[p].llen=tree[p].rlen=tree[p].m=0;

return ;
}
down(p);

int mid = (tree[p].l+tree[p].r)>>1;
if(mid>=r){ins(p*2,l,r);}
else if(mid<l){ins(p*2+1,l,r);}
else
{
ins(p*2,l,mid);

ins(p*2+1,mid+1,r);

}
spread(p);

}

void del(int p,int l,int r)
{
if(tree[p].l==l&&tree[p].r==r)
{
tree[p].m=tree[p].llen=tree[p].rlen=tree[p].r-tree[p].l+1;
return ;
}
down(p);
int mid = (tree[p].l+tree[p].r)>>1;
if(mid>=r){del(p*2,l,r);
}
else if(mid<l){del(p*2+1,l,r);
}
else
{
del(p*2,l,mid);

del(p*2+1,mid+1,r);

}
spread(p);
}

int search(int p,int ps)
{
down(p);
if(tree[p].m<ps)return -1;
if(tree[p].m>=ps)
{
if(tree[p*2].m>=ps){return search(p*2,ps);}
else if((tree[p*2].rlen+tree[p*2+1].llen)>=ps)
{
return tree[p*2].r-tree[p*2].rlen+1;
}

}

return search(p*2+1,ps);

}

int main()
{
int m,t,x,y;

while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,1,n);

while(m--)
{
scanf("%d",&t);
if(t==1)
{
scanf("%d",&x);
int l = search(1,x);

if(l!=-1)
{
ins(1,l,l+x-1);

printf("%d/n",l);
}
else
{

printf("0/n");
}

}
else
{
scanf("%d%d",&x,&y);
if((x+y-1)>n)
{

del(1,x,n);
}
else
{
del(1,x,x+y-1);
}

}
}

}

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