经典问题:不断更新查找区间连续递增序列(区间合并模板+单点更新)(3308)
2016-04-02 17:35
387 查看
LCIS
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6068 Accepted Submission(s): 2635
[align=left]Problem Description[/align]
Given n integers.
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
[align=left]Input[/align]
T in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).
[align=left]Output[/align]
For each Q, output the answer.
[align=left]Sample Input[/align]
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
[align=left]Sample Output[/align]
1 1 4 2 3 1 2 5
线段树的问题多借助画图来理解。lsum,rsum,msum分别代表从开始,从末尾,整个序列的最大连续递增子序列,最关键的在于pushup操作时,合并区间的问题:这里需要考虑全面,首先lsum[rt]可能跨过中点m,当然相对应的rsum[rt]也可能会跨过,其次,最长的一段子序列可能是中间一段跨过中点m的子序列,所以这些情况都需要分别考虑。要注意rt的左子树区间长度是len-(len>>1)(一定要加括号,否则会错!且很难察觉!),右子树的区间长度是len>>1。
/*------------------Header Files------------------*/ #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <algorithm> #include <cstdlib> #include <ctype.h> #include <cmath> #include <stack> #include <queue> #include <deque> #include <map> #include <vector> #include <set> #include <limits.h> using namespace std; /*------------------Definitions-------------------*/ #define LL long long #define uLL unsigned long long #define PI acos(-1.0) #define INF 0x3F3F3F3F #define MOD 9973 #define MAX 100050 #define lson rt<<1,l,m #define rson rt<<1|1,m+1,r /*---------------------Work-----------------------*/ int num[MAX]; int lsum[MAX<<2],rsum[MAX<<2],msum[MAX<<2]; //线段树空间一定要开四倍,刚开始开两倍WA一次 int n,m; void pushup(int rt,int l,int r) { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; msum[rt]=max(msum[rt<<1],msum[rt<<1|1]); int m=(l+r)>>1,len=r-l+1; //len是父亲结点的区间长度 if(num[m]<num[m+1]) //处理区间合并问题,既有lsum[rt],也有rsum[rt]和msum[rt] { //左右,右左和中间 if(lsum[rt<<1]==(len-(len>>1))) //注意括号不要忘了 lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt<<1|1]==(len>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(msum[rt],rsum[rt<<1]+lsum[rt<<1|1]); } } void build(int rt,int l,int r) { if(l==r) { msum[rt]=lsum[rt]=rsum[rt]=1; return ; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt,l,r); } void update(int rt,int l,int r,int p) { if(l==r) return ; int m=(l+r)>>1; if(p<=m) update(lson,p); else update(rson,p); pushup(rt,l,r); } int query(int rt,int l,int r,int L,int R) { if(L<=l&&R>=r) return msum[rt]; int m=(l+r)>>1; if(R<=m) return query(lson,L,R); //完全包含在左子树区间内 if(L>m) return query(rson,L,R); //完全包含在右子树区间内 int a,b; //左右子树区间都有成分在其中 a=query(lson,L,R); b=query(rson,L,R); int ans=max(a,b); if(num[m]<num[m+1]) { int c; c=min(m-L+1,rsum[rt<<1])+min(R-m,lsum[rt<<1|1]); //理解这一步 ans=max(ans,c); } return ans; } void work() { int T; cin>>T; while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",num+i); build(1,1,n); char ch[10]; int a,b; while(m--) { scanf("%s%d%d",ch,&a,&b); if(ch[0]=='U') { a++; num[a]=b; update(1,1,n,a); } else if(ch[0]=='Q') { a++,b++; printf("%d\n",query(1,1,n,a,b)); } } } } /*------------------Main Function------------------*/ int main() { //freopen("test.txt","r",stdin); work(); return 0; }
相关文章推荐
- ZOJ_2339_Hyperhuffman
- 虚拟机的安装
- 计时器Timer
- POJ 1258 Agri-Net 最小生成树
- HDU1087 Super Jumping! Jumping! Jumping!
- POJ 1258 Agri-Net 最小生成树
- 不用加减乘除做加法
- 分布式Web应用----zookeeper基本工作原理
- IOS学习之——库 静态库 动态库的学习和使用
- python3新特点
- markdown语法例子
- RxJava实例(三)
- 面向对象程序设计
- linux基础之命令Rsync
- 使用RDO方式安装 Openstack教程
- Android studio 布局文件变全黑
- 树的实现 分级文件系统
- 昨天晚上在舅舅家吃饭,得知已经做完肾结石手术
- 关于SQLite数据库使用的注意事项
- git--时空穿梭机--ife任务9