HDU_3308_线段树_区间合并
LCIS
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6166 Accepted Submission(s): 2675
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].
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).
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
1
4
2
3
1
2
5
看了题解,从下午做到晚上。。。然而看网上说是一道简单的区间合并。。。桑心。。。
给出序列,可单点更新,求最长连续递增子列的长度。
每一段记录
struct Node
{
int l,r,len; //线段树中的左右端点,以及序列长度
int ln,rn; //这个线段上的序列左右端点
int lm,rm,nm; //包含左端点,包含右端点,整段的最长递增连续子列长度
} tree[maxn<<2];
一个序列(rt)中的最长连续递增子列的长度(nm)是 max(tree[rt<<1].nm,tree[rt<<1|1].nm)和满足tree[rt<<1].rn<tree[rt<<1|1].ln(左孩子的右端点小于右孩子的左端点)条件下的tree[rt<<1].rm+tree[rt<<1|1].lm中较大者。更新点后pushup和query就是用这个思想。
第一波超时,是因为mid=(l+r)/2,用位运算更快,mid=(l+r)>>1
之前查询函数写的有问题。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1 struct Node
{
int l,r,len;
int ln,rn;
int lm,rm,nm;
} tree[maxn<<]; int num[]; void pushup(int rt)
{
tree[rt].ln=tree[rt<<].ln;
tree[rt].rn=tree[rt<<|].rn;
tree[rt].lm=tree[rt<<].lm;
tree[rt].rm=tree[rt<<|].rm;
tree[rt].nm=max(tree[rt<<].nm,tree[rt<<|].nm);
if(tree[rt<<].rn<tree[rt<<|].ln)
{
if(tree[rt].lm==tree[rt<<].len)
tree[rt].lm+=tree[rt<<|].lm;
if(tree[rt].rm==tree[rt<<|].len)
tree[rt].rm+=tree[rt<<].rm;
tree[rt].nm=max(tree[rt].nm,tree[rt<<].rm+tree[rt<<|].lm);
}
} void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].len=r-l+;
if(l==r)
{
tree[rt].lm=tree[rt].rm=tree[rt].nm=;
tree[rt].ln=tree[rt].rn=num[l];
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
pushup(rt);
} void update(int pos,int x,int l,int r,int rt)
{
if(l==pos&&r==pos)
{
tree[rt].ln=tree[rt].rn=x;
return;
}
int mid=(l+r)>>;
if(pos<=mid)
update(pos,x,lson);
else
update(pos,x,rson);
pushup(rt);
} int query(int L,int R,int l,int r,int rt)
{
if(L==l&&r==R)
return tree[rt].nm;
int mid=(l+r)>>;
if(R<=mid)
return query(L,R,lson);
else if(L>mid)
return query(L,R,rson);
else
{
int ll=query(L,mid,lson),ans=;
int rr=query(mid+,R,rson);
if(tree[rt<<].rn<tree[rt<<|].ln)
ans=min(mid-L+,tree[rt<<].rm)+min(R-mid,tree[rt<<|].lm);
return max(ans,max(ll,rr));
}
}
/*
int query(int l,int r,int i)//查询最大的LCIS
{
if(tree[i].l>=l && tree[i].r<=r)
{
return tree[i].nm;
}
int mid = (tree[i].l+tree[i].r)>>1,ans = 0;
if(l<=mid)
ans = max(ans,query(l,r,2*i));
if(r>mid)
ans = max(ans,query(l,r,2*i+1));
if(tree[2*i].rn < tree[2*i+1].ln)
ans = max(ans , min(mid-l+1,tree[2*i].rm)+min(r-mid,tree[2*i+1].lm));
return ans;
}*/ int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=; i<=n; i++)
scanf("%d",&num[i]);
build(,n,);
//cout<<tree[9].nm<<endl;
//cout<<"*"<<endl; for(int i=; i<m; i++)
{
char str[];
int a,b;
scanf("%s%d%d",str,&a,&b);
if(str[]=='U')
update(a+,b,,n,);
else if(str[]=='Q')
printf("%d\n",query(a+,b+,,n,));
}
}
return ;
}
HDU_3308_线段树_区间合并的更多相关文章
- 线段树:CDOJ1592-An easy problem B (线段树的区间合并)
An easy problem B Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...
- 线段树的区间合并 B - LCIS
B - LCIS HDU - 3308 这个是一个很简单很明显的线段树的区间合并,不过区间合并的题目都还是有点难写,建议存个板子. #include <cstdio> #include & ...
- CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)
题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...
- Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并
D. Developing Game Pavel is going to make a game of his dream. However, he knows that he can't mak ...
- 线段树_区间加乘(洛谷P3373模板)
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字 ...
- [HDOJ3308]LCIS(线段树,区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题意:给定n个数,两个操作: U A B:将位置A的数值改成B Q A B:查询[A,B]内最长 ...
- POJ 2750 Potted Flower(线段树的区间合并)
点我看题目链接 题意 : 很多花盆组成的圆圈,每个花盆都有一个值,给你两个数a,b代表a位置原来的数换成b,然后让你从圈里找出连续的各花盆之和,要求最大的. 思路 :这个题比较那啥,差不多可以用DP的 ...
- POJ 3667 & HDU 3308 & HDU 3397 线段树的区间合并
看到讲课安排上 线段树有一节课"区间合并" 我是迷茫的 因为并没有见过 然后了解了一下题目 发现以前写过 还是很麻烦的树链剖分 大概是 解决带修改的区间查询"连续问题&q ...
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
随机推荐
- Ubuntu查看和写入系统日志
一.背景 Linux将大量事件记录到磁盘上,它们大部分以纯文本形式存储在/var/log目录中.大多数日志条目通过系统日志守护进程syslogd,并被写入系统日志. Ubuntu包括以图形方式或从命令 ...
- 非常适合新手的jq/zepto源码分析03
zepto.fragment = function(html, name, properties) { var dom, nodes, container // 如果是简单的标签<div> ...
- ASUS VivoTab RT TF600T忘记系统登录密码,怎么办?
ASUS VivoTab RT TF600T若忘记系统登录账户密码,可以通过以下两种方式尝试初始化电脑.但是请注意,初始化电脑将删除所有个人文件和应用,并还原电脑设置为默认值. 方法一:通过键盘操作 ...
- SPOJ QTREE2 lct
题目链接 题意: 给一棵树.有边权 1.询问路径的边权和 2.询问沿着路径的第k个点标. 思路:lct裸题. #include <iostream> #include <fstrea ...
- Cocos2d-HTML5搭载nodejs express3
源代码 已经上传到github Cocos2d-HTML5 入门第一天搭载了express3 server.Cocos2d-html5配置改了不少路径,改得有点乱. 今天又重搭了一遍server,力求 ...
- C++类库
转载自:http://blog.csdn.net/Augusdi/article/details/8989763 基础类 一.C++标准库 1. Dinkumware C++ Library 参考站点 ...
- LeetCode 884. Uncommon Words from Two Sentences (两句话中的不常见单词)
题目标签:HashMap 题目给了我们两个句子,让我们找出不常见单词,只出现过一次的单词就是不常见单词. 把A 和 B 里的word 都存入 map,记录它们出现的次数.之后遍历map,把只出现过一次 ...
- Codeforces Round #211 (Div. 2)B. Fence
B. Fence time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...
- 将canvas画布内容转化为图片(toDataURL(),创建url)
将canvas画布内容转化为图片(toDataURL(),创建url) 总结 1.现在的浏览器都支持右键另存为图片的方法来将canvas画布内容转化为图片 2.在代码里面可以通过toDataURL() ...
- sql server数据库添加记录
转自:http://jingyan.baidu.com/article/f25ef254449a9a482c1b8293.html