hdu 3308(线段树的区间合并)
2011-09-14 20:21
344 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:给你一串数(最多有10^5个,值最大有10^5),给你两个operation, U x y,表示将第x个值替换为y, Q x y表示查询x到y中最长连续子序列的个数,操作的次数不超过10^5个
分析: 啊,这个题显然用线段树做,我们可以设置线段树的一些域,l,r,lz,rz,mnum,分别表示区间的左右边界,区间左边连续的递增序列个数,区间右边连续测递增序列个数,区间中最大的递增序列的个数,之后就是维护的问题了,详情见代码!!
代码:
题意:给你一串数(最多有10^5个,值最大有10^5),给你两个operation, U x y,表示将第x个值替换为y, Q x y表示查询x到y中最长连续子序列的个数,操作的次数不超过10^5个
分析: 啊,这个题显然用线段树做,我们可以设置线段树的一些域,l,r,lz,rz,mnum,分别表示区间的左右边界,区间左边连续的递增序列个数,区间右边连续测递增序列个数,区间中最大的递增序列的个数,之后就是维护的问题了,详情见代码!!
代码:
#include<stdio.h> #include<string.h> #define N 100005 //const int N=100005; int a ; struct node { int l,r; //区间的左右边界 int lz,rz;//分别表示左右两边连续的递增递减的序列个数 int mnum; //表示区间里的最大连续的个数 }tree[N*4]; int Max(int a,int b) { return a>b?a:b; } void bulid(int rt,int l, int r)// 建立线段树,并初始化lz,rz,mnum; { tree[rt].l=l; tree[rt].r=r; tree[rt].lz=0; tree[rt].rz=0; tree[rt].mnum=0; if(l==r) { tree[rt].lz=1;//若为根节点那么区间左边界开始的递增数目1 tree[rt].rz=1;//同上 tree[rt].mnum=1;//区间的最大递增数目也为1 return; } int mid=(l+r)>>1; bulid(2*rt,l,mid);//建左子树 bulid(2*rt+1,mid+1,r);//建右子树 //回溯更新区间值 if(tree[2*rt].lz==(mid-l+1)&&a[mid+1]>a[mid])//更新区间左边连续递增序列的个数 tree[rt].lz=tree[2*rt].lz+tree[2*rt+1].lz; else tree[rt].lz=tree[2*rt].lz; if(tree[2*rt+1].rz==(r-mid)&&a[mid+1]>a[mid]) //更新区间右边连续递增序列的个数 tree[rt].rz=tree[2*rt+1].rz+tree[2*rt].rz; else tree[rt].rz=tree[2*rt+1].rz; tree[rt].mnum=Max(tree[2*rt].mnum,tree[2*rt+1].mnum);//更新区间中最大连续连续递增序列的值 if(a[mid+1]>a[mid]) tree[rt].mnum=Max(tree[2*rt].rz+tree[2*rt+1].lz,tree[rt].mnum); } void update(int rt,int x,int y,int l, int r) { if(l==r&&x==l) { a[x]=y; return; } int mid=(l+r)>>1; if(x<=mid) update(2*rt,x,y,l,mid); else update(2*rt+1,x,y,mid+1,r); //这里的回溯更新同bulid函数里的一样 if(tree[2*rt].lz==(mid-l+1)&&a[mid+1]>a[mid]) tree[rt].lz=tree[2*rt].lz+tree[2*rt+1].lz; else tree[rt].lz=tree[2*rt].lz; if(tree[2*rt+1].rz==(r-mid)&&a[mid+1]>a[mid]) tree[rt].rz=tree[2*rt+1].rz+tree[2*rt].rz; else tree[rt].rz=tree[2*rt+1].rz; tree[rt].mnum=Max(tree[2*rt].mnum,tree[2*rt+1].mnum); if(a[mid+1]>a[mid]) tree[rt].mnum=Max(tree[2*rt].rz+tree[2*rt+1].lz,tree[rt].mnum); } //查询结果 int search(int rt,int l,int r) { int ans1,ans,ans2 , ans3,ans4; if(tree[rt].l==l&&tree[rt].r==r) return tree[rt].mnum; int mid=(tree[rt].l+tree[rt].r)>>1; if(r<=mid)return search(2*rt,l,r); else if(l>mid)return search(2*rt+1,l,r); else { //注意这里 if(tree[2*rt].rz>=mid-l+1) ans1=mid-l+1; else ans1=tree[2*rt].rz; if(tree[2*rt+1].lz>=r-mid) ans2=r-mid; else ans2=tree[2*rt+1].lz; if(a[mid+1]>a[mid]) ans=ans1+ans2; else ans=0; ans3=search(2*rt,l,mid); ans4=search(2*rt+1,mid+1,r); if(ans) return Max(ans,Max(ans3,ans4)); return Max(Max(ans1,ans2),Max(ans3,ans4)); } } void print(int rt) { printf("%d %d %d %d %d\n",tree[rt].l, tree[rt].r,tree[rt].lz, tree[rt].rz,tree[rt].mnum); if(tree[rt].l==tree[rt].r) return; print(2*rt); print(2*rt+1); } int main () { int t,n,q,i,x,y; char ch[3]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); for(i=0;i<n;i++) scanf("%d",&a[i]); bulid(1,0,n-1); getchar(); for(i=0;i<q;i++) { scanf("%s%d%d",ch,&x,&y); //printf("%s\n",ch); if(ch[0]=='Q') printf("%d\n",search(1,x,y)); else if(ch[0]=='U') update(1,x,y,0,n-1); } } return 0; }
相关文章推荐
- 【HDU - 3308】 LCIS 【线段树+单点更新+区间合并】
- HDU 3308 线段树 区间合并模板题
- HDU 3308 LCIS(线段树区间合并)
- hdu 3308 线段树+区间合并
- HDU 3308 LCIS(线段树区间合并)
- hdu 3308 LCIS (线段树+单点更新+区间合并)
- [HDU 3308]LCIS[线段树][区间合并]
- hdu 3308 线段树单点更新 区间合并
- hdu 3308 LCIS(线段树区间合并)
- HDU 3308 LCIS 最长上升字串(线段树区间合并)
- HDU 3308【线段树--c++版区间合并,dp】
- HDU 3308 LCIS(线段树单点更新区间合并)
- hdu 3308 线段树区间合并
- HDU 3308——LCIS(线段树,区间合并,最长连续递增子序列)
- HDU 3308 LCIS 线段树的单点更新,区间合并
- HDU 3308 LCIS 线段树 区间合并 入门题
- HDU_3308_线段树_区间合并
- (简单) HDU 3308 LCIS,线段树+区间合并。
- HDU 3308 LCIS(线段树区间合并)
- hdu 3308 LCIS(线段树区间合并)