维护直线的线段树: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 老师交给小可可一个维护数列的任务,现在小可 ...
随机推荐
- SpringCloud之Eureka(注册中心集群篇)
一:集群环境搭建 第一步:我们新建两个注册中心工程一个叫eureka_register_service_master,另一个叫eureka_register_service_backup eureka ...
- Anaconda3+python3环境下如何创建python2环境(win+Linux下适用,同一个anaconda下py2/3共存)
本人之前已经在anaconda环境下已经安装了python3的环境,现在因为一些需求,要安装python2环境 1.打开anaconda的anaconda prompt查看当前环境: conda in ...
- GridView Postback后出错Operation is not valid due to the current state of the object.
一.问题起因 最近项目中有一页面第一次search后正常,但是再次点击其它任何按钮都会报错,亦即postback后页面有问题,经检查是由于页面有一GridView且数据量极大,记录大概有上千条,这儿解 ...
- Struts2笔记2--动态方法调用和Action接收请求方式
动态方法调用(在请求的时候,再明确具体的响应方法,配置的时候不明确): LoginAction类中有两个方法some和second 1. 动态方法的调用(修改常量struts.enable.Dynam ...
- 关于Java IO与NIO知识都在这里
由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读.每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾. Java面试通关手册(Java学习 ...
- python3之线程与进程
1.CPU运行原理 我们都知道CPU的根本任务就是执行指令,对计算机来说最终都是一串由“0”和“1”组成的序列.CPU从逻辑上可以划分成3个模块,分别是控制单元.运算单元和存储单元,这三部分由CPU内 ...
- android开发中常用的快捷键
Eclipse快捷键-方便查找,呵呵,记性不好 行注释/销注释 Ctrl+/ 块注释/销注释/XML注释 Ctrl+Shift+/ Ctrl+Shift+\查找 查找替换 Ctrl+H Ctr ...
- Linux内核跟踪之trace框架分析【转】
转自:http://blog.chinaunix.net/uid-20543183-id-1930846.html ---------------------------------------- ...
- 从此编写 Bash 脚本不再难【转】
从此编写 Bash 脚本不再难 原创 Linux技术 2017-05-02 14:30 在这篇文章中,我们会介绍如何通过使用 bash-support vim 插件将 Vim 编辑器安装和配置 为一个 ...
- 微软Holographic将更名为Windows Mixed Reality
微软Holographic将更名为Windows Mixed Reality ----世界变化好快. 还没来得及细细品味,它就已经更名了. 程序员的焦虑,处在一个信息大爆炸的年代,大数据,云计算,机 ...