维护直线的线段树:Bzoj1568,Bzoj3938(Uoj88)
有这样一类线段树,可以维护一些直线方程并对每个点求出最大值。
首先先看BZOJ1568,输入给你条直线的方程,你需要对于指定的位置求出最大的函数值。
看到数据范围nlog^2n可做,考虑用线段树去维护。对于每个区间,怎么维护这个区间最高的直线呢?
显然,对于这个区间而言,最高的直线在各个位置都可能是不同的,看起来不是很可做。但是,我们能对于每个长度为1的区间维护最高的直线。
然而这样需要把修改push到底,时间复杂度为线性,所以应该怎么办呢?
考虑标记永久化,对于每个区间,维护其中点最高的直线。然后查询时对于跨越的多个区间的答案取max,这样可以完成查询。
怎么修改呢?考虑在某个区间上有两条直线(一条原来的,一条新加的),如果一条在整个区间都在另一条之上,那么可以把下面的那条线扔掉,直接返回。否则把中点较高的那一条留在这个区间,另外一条向(这条线)比留下的更高的一个子区间下放。
考虑这样为什么是对的,因为如果一条线在中点比另一条高,那么在某一边区间这条线一定完全“碾压”另一条线,另外一条是没有用的。所以只把另外一条在另一个子区间下放即可(自己画图或脑补一下就明白了)。
这个东西的复杂度是log^2n,因为最多修改logn个区间,对于每个区间最多下放logn层。
然后问题就解决了。
上代码:
BZOJ1568:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define debug cout
using namespace std;
const int maxn=5e4+1e2; int l[maxn<<],r[maxn<<],lson[maxn<<],rson[maxn<<];
int mid[maxn<<];
double k[maxn<<],b[maxn<<];
int n,m,cnt; inline double f(const double &k,const double &b,const int &x) {
return k * ( x - ) + b;
}
inline void build(int pos,int ll,int rr) {
l[pos] = ll , r[pos] = rr;
if( ll == rr )
return;
mid[pos] = ( ll + rr ) >> ;
build(lson[pos]=++cnt,ll,mid[pos]);
build(rson[pos]=++cnt,mid[pos]+,rr);
}
inline void update(int pos,double kk,double bb) {
if( f(kk,bb,l[pos]) <= f(k[pos],b[pos],l[pos]) && f(kk,bb,r[pos]) <= f(k[pos],b[pos],r[pos]) )
return;
if( l[pos] == r[pos] ) {
k[pos] = kk , b[pos] = bb;
return;
}
if( kk > k[pos] ) {
if( f(kk,bb,mid[pos]) > f(k[pos],b[pos],mid[pos]) ) {
update(lson[pos],k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(rson[pos],kk,bb);
}
else {
if( f(kk,bb,mid[pos]) > f(k[pos],b[pos],mid[pos]) ) {
update(rson[pos],k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(lson[pos],kk,bb);
}
}
inline double query(int pos,int tar) {
if( l[pos] == r[pos] )
return f(k[pos],b[pos],tar);
if( tar <= mid[pos] )
return max( f(k[pos],b[pos],tar) , query(lson[pos],tar) );
else if( tar > mid[pos] )
return max( f(k[pos],b[pos],tar) , query(rson[pos],tar) );
} int main() {
static char com[];
static double qq,kk,bb;
scanf("%d",&m) , n = 5e4;
build(cnt=,,n);
for(int i=,p;i<=m;i++) {
scanf("%s",com);
if( *com == 'Q' ) {
scanf("%d",&p);
qq = query(,p);
printf("%d\n",((int)qq)/);
}
else {
scanf("%lf%lf",&bb,&kk);
update(,kk,bb);
}
}
return ;
}
UOJ88:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define lli long long int
#define debug cout
using namespace std;
const int maxn=1e5+1e2,maxq=6e5+1e2; lli srt[maxq]; inline lli f(const lli &k,const lli &b,const int &x) {
return k * srt[x] + b;
} int lson[maxq<<],rson[maxq<<];
struct SegmentTree {
int cnt;
lli k[maxq<<],b[maxq<<]; inline void build(int pos,int ll,int rr) {
if( ll == rr )
return;
const int mid = ( ll + rr ) >> ;
build(lson[pos]=++cnt,ll,mid);
build(rson[pos]=++cnt,mid+,rr);
}
inline void update(int pos,int l,int r,int ll,int rr,lli kk,lli bb) {
if( rr < l || r < ll )
return;
const int mid = ( l + r ) >> ;
if( ll <= l && r <= rr ) {
if( f(kk,bb,l) <= f(k[pos],b[pos],l) && f(kk,bb,r) <= f(k[pos],b[pos],r) )
return;
if( l == r ) {
k[pos] = kk , b[pos] = bb;
return;
}
if( kk > k[pos] ) {
if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) {
update(lson[pos],l,mid,l,r,k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(rson[pos],mid+,r,ll,rr,kk,bb);
}
else {
if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) {
update(rson[pos],mid+,r,l,r,k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(lson[pos],l,mid,ll,rr,kk,bb);
}
}
update(lson[pos],l,mid,ll,rr,kk,bb);
update(rson[pos],mid+,r,ll,rr,kk,bb);
}
inline lli query(int pos,int l,int r,int tar) {
lli ret = f(k[pos],b[pos],tar);
if( l == r )
return ret;
const int mid = ( l + r ) >> ;
if( tar <= mid )
ret = max( ret , query(lson[pos],l,mid,tar) );
else
ret = max( ret , query(rson[pos],mid+,r,tar) );
return ret;
}
}up,down; int s[maxn],st[maxq],ed[maxq];
lli k[maxq],b[maxq];
int ope[maxq][];
int n,m,len=,cnt;
int v[maxn]; inline lli getb(int pos,int tme,lli newk) {
lli alpha = f(k[pos],b[pos],tme);
return alpha - newk * srt[tme];
}
inline void add(int pos,int tt,lli kk,lli bb=) {
k[++cnt] = kk;
if( !bb )
bb = getb(s[pos],tt,kk);
b[cnt] = bb;
st[cnt] = tt , ed[cnt] = len;
if( s[pos] )
ed[s[pos]] = tt;
s[pos] = cnt;
} inline void init() {
sort(srt+,srt++len);
len = unique(srt+,srt++len) - srt - ;
for(int i=;i<=m;i++)
ope[i][] = lower_bound(srt+,srt++len,ope[i][]) - srt;
for(int i=;i<=n;i++)
add(i,,,v[i]);
for(int i=;i<=m;i++)
if( *ope[i] ) {
add(ope[i][],ope[i][],ope[i][]);
} up.build(up.cnt=,,len); for(int i=;i<=cnt;i++) {
up.update(,,len,st[i],ed[i],k[i],b[i]);
down.update(,,len,st[i],ed[i],-k[i],-b[i]);
}
} inline void work() {
static lli ans;
for(int i=;i<=m;i++)
if( ! *ope[i] ) {
ans = max( up.query(,,len,ope[i][]) , down.query(,,len,ope[i][]) );
printf("%lld\n",ans);
}
} int main() {
static char com[];
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",v+i);
for(int i=;i<=m;i++) {
scanf("%d",&ope[i][]);
srt[++len] = ope[i][];
scanf("%s",com);
if( *com == 'c' ) {
ope[i][] = ;
scanf("%d%d",&ope[i][],&ope[i][]);
}
}
init();
work(); return ;
}
上面的代码是无法通过BZOJ3938的,因为少了一个return。
BZOJ3938:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define lli long long int
#define debug cout
using namespace std;
const int maxn=1e5+1e2,maxq=6e5+1e2; lli srt[maxq]; inline lli f(const lli &k,const lli &b,const int &x) {
return k * srt[x] + b;
} int lson[maxq<<],rson[maxq<<];
struct SegmentTree {
int cnt;
lli k[maxq<<],b[maxq<<]; inline void build(int pos,int ll,int rr) {
if( ll == rr )
return;
const int mid = ( ll + rr ) >> ;
build(lson[pos]=++cnt,ll,mid);
build(rson[pos]=++cnt,mid+,rr);
}
inline void update(int pos,int l,int r,int ll,int rr,lli kk,lli bb) {
if( rr < l || r < ll )
return;
const int mid = ( l + r ) >> ;
if( ll <= l && r <= rr ) {
if( f(kk,bb,l) <= f(k[pos],b[pos],l) && f(kk,bb,r) <= f(k[pos],b[pos],r) )
return;
if( l == r ) {
k[pos] = kk , b[pos] = bb;
return;
}
if( kk > k[pos] ) {
if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) {
update(lson[pos],l,mid,l,r,k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(rson[pos],mid+,r,ll,rr,kk,bb);
}
else {
if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) {
update(rson[pos],mid+,r,l,r,k[pos],b[pos]);
k[pos] = kk , b[pos] = bb;
}
else
update(lson[pos],l,mid,ll,rr,kk,bb);
}
return;
}
update(lson[pos],l,mid,ll,rr,kk,bb);
update(rson[pos],mid+,r,ll,rr,kk,bb);
}
inline lli query(int pos,int l,int r,int tar) {
lli ret = f(k[pos],b[pos],tar);
if( l == r )
return ret;
const int mid = ( l + r ) >> ;
if( tar <= mid )
ret = max( ret , query(lson[pos],l,mid,tar) );
else
ret = max( ret , query(rson[pos],mid+,r,tar) );
return ret;
}
}up,down; int s[maxn],st[maxq],ed[maxq];
lli k[maxq],b[maxq];
int ope[maxq][];
int n,m,len=,cnt;
int v[maxn]; inline lli getb(int pos,int tme,lli newk) {
lli alpha = f(k[pos],b[pos],tme);
return alpha - newk * srt[tme];
}
inline void add(int pos,int tt,lli kk,lli bb=) {
k[++cnt] = kk;
if( !bb )
bb = getb(s[pos],tt,kk);
b[cnt] = bb;
st[cnt] = tt , ed[cnt] = len;
if( s[pos] )
ed[s[pos]] = tt;
s[pos] = cnt;
} inline void init() {
sort(srt+,srt++len);
len = unique(srt+,srt++len) - srt - ;
for(int i=;i<=m;i++)
ope[i][] = lower_bound(srt+,srt++len,ope[i][]) - srt;
for(int i=;i<=n;i++)
add(i,,,v[i]);
for(int i=;i<=m;i++)
if( *ope[i] ) {
add(ope[i][],ope[i][],ope[i][]);
} up.build(up.cnt=,,len); for(int i=;i<=cnt;i++) {
up.update(,,len,st[i],ed[i],k[i],b[i]);
down.update(,,len,st[i],ed[i],-k[i],-b[i]);
}
} inline void work() {
static lli ans;
for(int i=;i<=m;i++)
if( ! *ope[i] ) {
ans = max( up.query(,,len,ope[i][]) , down.query(,,len,ope[i][]) );
printf("%lld\n",ans);
}
} inline int getint() {
int ret = , fix = ;
char ch = getchar();
while( !isdigit(ch) )
fix = ch == '-' ? - : fix,
ch = getchar();
while( isdigit(ch) )
ret = ret * + ch - '',
ch = getchar();
return ret * fix;
}
int main() {
static char com[];
n = getint() , m = getint();
for(int i=;i<=n;i++)
v[i] = getint();
for(int i=;i<=m;i++) {
ope[i][] = getint();
srt[++len] = ope[i][];
scanf("%s",com);
if( *com == 'c' ) {
ope[i][] = ;
ope[i][] = getint() , ope[i][] = getint();
}
}
init();
work(); return ;
}
对了,今天我似乎达成成就:吓跑小学妹......话说我有那么凶神恶煞吗......
维护直线的线段树:Bzoj1568,Bzoj3938(Uoj88)的更多相关文章
- BZOJ_1798_[AHOI2009]维护序列_线段树
BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...
- [AHOI 2009] 维护序列(线段树模板题)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...
- CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...
- 1798. [AHOI2009]维护序列【线段树】
Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeO ...
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...
- 维护gcd的线段树 补发一波。。。
基础线段树(辣鸡的不行) 发现自己线段树除了会维护加法和乘法就啥也不会了QWQ太菜了 瞎写了一个维护gcd的 首先,gcd(x,y)= gcd(x,y-x) 并且很容易推广到n个数,所以我们可以把原数 ...
- Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...
随机推荐
- 36、IO流概述和分类
IO流概述 IO流的主要作用是用来处理设备之间的数据传输,例如可以使用IO流将一台电脑硬盘里面的照片传输到另一台电脑上面,即将照片转换为字节,然后将字节传到另一台电脑上面,另一台电脑接收后,可以将这些 ...
- 常见踩坑案例(二)-Request method 'POST' not supported
一 前言 最近涉及到与前后端的数据对接,按道理来说没一点压力结果被一前端童鞋带坑里去了(不过也是很久没写过这种前后端分离进行联调的事情了,如果是一个人全套弄的话就不会出现下面问题). 二 Reques ...
- NOIP 2016 迟来的满贯
17-03-22,雨 17-03-22,一个特别重要的日子 在这一天,本蒻攻克了NOIP 2016最难的一题,D1T2——天天爱跑步 实现了NOIP 2016的AK! YAYAYAYAYAYAY 自然 ...
- 【Python】POST上传APK检测是否存在ZipperDown漏洞
前言 用POST的方式上传文件,检测APK是否存在ZipperDown漏洞. 代码 # authour:zzzhhh # 2018.08.08 # check ZipperDown # -*- cod ...
- crond检查服务状态
代码如下: * */1 * * * /etc/init.d/ntpd status;if [ $? -ne 0 ];then /etc/init.d/ntpd start; fi
- Tslib移植与分析【转】
转自:http://blog.csdn.net/water_cow/article/details/7215308 目标平台:LOONGSON-1B开发板(mips32指令集)编译平台:x86PC-- ...
- mysql测试工具 -> mysqlslap
一.简介 mysqlslap是mysql自带的基准测试工具 优点:查询数据,语法简单,灵活容易使用.该工具可以模拟多个客户端同时并发的向服务器发出查询更新,给出了性能测试数据而且提供了多种引擎的性能比 ...
- python基础-各模块文章导航
python基础学习日志day5-各模块文章导航 python基础学习日志day5---模块使用 http://www.cnblogs.com/lixiang1013/p/6832475.html p ...
- java基础30 List集合下的LinkedList集合
单例集合体系: ---------| collection 单例集合的根接口--------------| List 如果实现了list接口的集合类,具备的特点:有序,可重复 注:集合 ...
- opencv(5)GUI
OpenCV的图形用户界面(Graphical User Interface, GUI)和绘图等相关功能也是很有用的功能,无论是可视化,图像调试还是我们这节要实现的标注任务,都可以有所帮助. 窗口循环 ...