杭电3308 LCIS(线段树区间合并)
2015-12-16 19:56
363 查看
线段树的学习真的是一件很不容易的事情.
漫长的道路望不到终点...繁杂的思路一时半会理不清T T
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5759 Accepted Submission(s): 2499
Problem Description
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].
Input
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).
Output
For each Q, output the answer.
Sample Input
Sample Output
题目大意:
给出n个数m个操作
U操作 把a位子上的数字改成b
Q操作 问区间(a,b)上最长连续递增子序列长度....(看起来好麻烦的样纸~)
这里先谈一下初始化的问题:
无论做什么事情我们一定要有输入和建树:
这里就要浅谈一下pushup的操作,pushuup在线段树里边起到几个作用;1.维护树内数据2.向上更新该更新的数据
所以建树的同时 要不断的pushup pushup pushup------
这里我们知道lsum和rsum以及msum的含义.所以如果是向上维护数据的话 当前区间lsum就可以递推给上边的lsum既lsum[rt]=lsum[rt*2].
这个时候细心的小伙伴就要问了(假设现在区间是(1,5))如果现在的lsum的值应该是5但是你现在最大的值也就是个3 你这上坟烧报纸烧的略有些明显啊.
既然细心的小伙伴知道现在最大的值也就是个3 这个时候我们呢 就要找到3这个罚分点 然后判断是否能够区间合并 完成3->5的操作.
这里贴上pushup的操作代码加以详解:
pushup的操作有了之后 ,我们建树的工程也就同时结束了.
接下来谈update(也就是U操作)
这部分还是比较好理解的 这里直接贴上代码和详解:
最后再来说query(查询)操作.
蓝后我们这里贴上完整的AC代码
漫长的道路望不到终点...繁杂的思路一时半会理不清T T
LCIS
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5759 Accepted Submission(s): 2499
Problem Description
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].
Input
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).
Output
For each Q, output the answer.
Sample Input
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
Sample Output
1 1 4 2 3 1 2 5
题目大意:
给出n个数m个操作
U操作 把a位子上的数字改成b
Q操作 问区间(a,b)上最长连续递增子序列长度....(看起来好麻烦的样纸~)
这里先谈一下初始化的问题:
const int maxn=100000+5; int msum[maxn<<2];//区间内最长连续递增子序列长度. int lsum[maxn<<2];//区间从左边第一个数开始算起 到区间最后一个数的连续递增序列长度(比如(1,5)区间内数据:2 3 5 4 1)这个时候这个数组里边存的数据是2(2,3) int rsum[maxn<<2];//右边的被(比如(1,5)区间内数据:5 4 1 2 3)这个时候数组里边存的数据是3(1,2,3) int num[maxn];//存入数据的数组(并不是树哦~)上边这部分的内容一定要理解透彻.
#include<iostream> #include<stdio.h> #include<string.h> using namespace std;//水一发头文件 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1//左右子树的快速调用写法~
无论做什么事情我们一定要有输入和建树:
int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)//这里输入强调 n个数的数据存入方式....跟树无关哦~. { scanf("%d",&num[i]); }
void build(int l,int r,int rt)//日常建树... { if(l==r) { msum[rt]=lsum[rt]=rsum[rt]=1;//这里自行理解0.0 return ; } int m = (l+r)>>1 ; build(lson) ; build(rson) ; pushup(l,r,rt) ;//主要还是通过建树的操作来印出来很关键的步骤. }
这里就要浅谈一下pushup的操作,pushuup在线段树里边起到几个作用;1.维护树内数据2.向上更新该更新的数据
所以建树的同时 要不断的pushup pushup pushup------
这里我们知道lsum和rsum以及msum的含义.所以如果是向上维护数据的话 当前区间lsum就可以递推给上边的lsum既lsum[rt]=lsum[rt*2].
这个时候细心的小伙伴就要问了(假设现在区间是(1,5))如果现在的lsum的值应该是5但是你现在最大的值也就是个3 你这上坟烧报纸烧的略有些明显啊.
既然细心的小伙伴知道现在最大的值也就是个3 这个时候我们呢 就要找到3这个罚分点 然后判断是否能够区间合并 完成3->5的操作.
这里贴上pushup的操作代码加以详解:
void pushup(int l,int r,int rt)//((1,5),2)区间(l,r)节点rt //以下配合上边所述的例子来走的. { lsum[rt]=lsum[rt*2]; rsum[rt]=rsum[rt*2+1]; msum[rt]=max(msum[rt*2],msum[rt*2+1]);//上边的语言描述尽我所能的解释了0.0 int m=(l+r)/2;//罚分点. int len=r-l+1;//区间长度 if(num[m]<num[m+1])//如果能有3->5的操作(也可以理解为能够区间合并) { if(lsum[rt]==len-(len/2))//首先我们要满足3的存在 lsum[rt]+=lsum[rt*2+1];//这个时候我们就获得5的存在了 if(rsum[rt]==len/2)//当然也有肯能是右边的3->5 rsum[rt]+=rsum[rt*2];//我们不能只看左边而忘记了右边~ msum[rt]=max(msum[rt],lsum[rt*2+1]+rsum[rt*2]);//msum用来存的数据是当前区间所求最大值. } }
pushup的操作有了之后 ,我们建树的工程也就同时结束了.
接下来谈update(也就是U操作)
这部分还是比较好理解的 这里直接贴上代码和详解:
void update(int p,int l,int r,int rt)//找到p之前不断的pushup.//修改数据的操作在主函数中已经搞定了. { if(l==r) return ; int m=(l+r)/2; if(p<=m) update(p,lson); else update(p,rson); pushup(l,r,rt); }
最后再来说query(查询)操作.
int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return msum[rt]; } int m=(l+r)>>1; if(R<=m)return query(L,R,lson); if(L>m)return query(L,R,rson);//左右区间的寻找. int a,b; a=query(L,R,lson); b=query(L,R,rson); int ans; ans=max(a,b);//ans首先取左右区间最大值. if(num[m]<num[m+1])//这里还有一个合并区间的问题. { int c; c=min(rsum[rt*2],m-L+1)+min(lsum[rt*2+1],R-m);//这里在纸上描描画画就懂咯~ ans=max(c,ans); } return ans; }
蓝后我们这里贴上完整的AC代码
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=100000+5; int msum[maxn<<2]; int lsum[maxn<<2]; int rsum[maxn<<2]; int num[maxn]; void pushup(int l,int r,int rt) { lsum[rt]=lsum[rt*2]; rsum[rt]=rsum[rt*2+1]; msum[rt]=max(msum[rt*2],msum[rt*2+1]); int m=(l+r)/2; int len=r-l+1; if(num[m]<num[m+1]) { if(lsum[rt]==len-(len/2)) lsum[rt]+=lsum[rt*2+1]; if(rsum[rt]==len/2) rsum[rt]+=rsum[rt*2]; msum[rt]=max(msum[rt],lsum[rt*2+1]+rsum[rt*2]); } } void build(int l,int r,int rt) { if(l==r) { msum[rt]=lsum[rt]=rsum[rt]=1; return ; } int m = (l+r)>>1 ; build(lson) ; build(rson) ; pushup(l,r,rt) ; } void update(int p,int l,int r,int rt)//找到p之前不断的pushup. { if(l==r) return ; int m=(l+r)/2; if(p<=m) update(p,lson); else update(p,rson); pushup(l,r,rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return msum[rt]; } int m=(l+r)>>1; if(R<=m)return query(L,R,lson); if(L>m)return query(L,R,rson); int a,b; a=query(L,R,lson); b=query(L,R,rson); int ans; ans=max(a,b); if(num[m]<num[m+1]) { int c; c=min(rsum[rt*2],m-L+1)+min(lsum[rt*2+1],R-m);//防炸专用. ans=max(c,ans); } return ans; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } build(1,n,1); while(m--) { char op[121]; scanf("%s",op); int a,b; scanf("%d%d",&a,&b); if(op[0]=='U') { a++; num[a]=b; update(a,1,n,1); } else { a++; b++; printf("%d\n",query(a,b,1,n,1)); } } } }
相关文章推荐
- 大端模式与小端模式、网络字节顺序与主机字节顺序 (经典)
- 安装11G数据库脚本
- python实践——批量统计mongodb数据库的集合大小
- Caused by: java.lang.IllegalArgumentException: Illegal character in scheme at index 0:
- Android读书笔记之Fragment入门
- MySQL 常用管理工具
- NodeJs oracledb无法完成删除数据项操作的处理方法
- python实践——批量统计mongodb数据库的集合大小
- android判断当前系统的语言
- 2049: [Sdoi2008]Cave 洞穴勘测
- MySQL 常用维护命令
- 已阻止跨源请求:同源策略禁止读取位于...的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
- GetKeyState()和GetAsyncKeyState()的区别
- 如何将android studio项目转换成eclipse
- 1215整理
- 头结点
- as为jar包关联源码
- MySQL 索引、试图、存过、函数、触发器
- 证明:素数对中间的数能被6整除
- Leetcode题解(十四)