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 语句最值得细看----多段联合 这个递归从最后开始往前联合。一般都要从后往前比较好。因为最小单位可以确定其值了,当然这里不需要这么考虑。
完整代码:
来看看poj的hotel吧 比较相似。把思想搞懂了就好做了。
看下图希望能够更好理解。
两天的对题目和代码的细细分析,终于搞懂理解了,o(∩_∩)o 哈哈
主要关键是往回来的时候当前结点下面的信息要被当前结点影响。当前结点区间全部被占下层的孩子就是更新。
记住找区间的时候
if(tree[p].l==l&&tree[p].r==r)
否则会去递归到底层,这样就时间并没有优化,线段树也不起作用了。
看代码:
序列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; }
相关文章推荐
- POJ 3667 Hotel & HDU 2871 Memory Control 线段树区间合并
- Poj 3667 Hotel + Hdu 4553 约会安排 (线段树最左空区间)
- POJ 3667 & HDU 3308 & HDU 3397 线段树的区间合并
- 线段树(区间合并) POJ 3667 Hotel
- poj 3667 Hotel 经典线段树区间合并
- POJ 3667 - Hotel(线段树+区间合并)
- POJ 3667 Hotel 线段树区间合并
- POJ 3667 Hotel 线段树 区间合并(成段更新)
- poj 3667 Hotel (线段树)
- POJ 3667——Hotel(线段树,区间合并)
- poj 3667 Hotel(线段树中级,区间合并)
- Poj 3667 Hotel 线段树 区间合并
- (Relax 线段树1.3)POJ 3667 Hotel(互不相交的线段的更新与统计)
- POJ 3667 Hotel(线段树区间合并)
- POJ 3667 Hotel (线段树区间最大连续长度)
- POJ 3667 Hotel 线段树区间合并
- POJ 3667 Hotel 线段树(区间合并)
- 【线段树】POJ 3667 Hotel 区间合并
- poj 3667 Hotel 线段树 内存分配问题
- POJ 3667 Hotel 线段树 区间合并