有这样一类线段树,可以维护一些直线方程并对每个点求出最大值。

首先先看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)的更多相关文章

  1. BZOJ_1798_[AHOI2009]维护序列_线段树

    BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...

  2. [AHOI 2009] 维护序列(线段树模板题)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...

  3. BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )

    线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...

  4. CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...

  5. 1798. [AHOI2009]维护序列【线段树】

    Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...

  6. bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeO ...

  7. 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树

    题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...

  8. 维护gcd的线段树 补发一波。。。

    基础线段树(辣鸡的不行) 发现自己线段树除了会维护加法和乘法就啥也不会了QWQ太菜了 瞎写了一个维护gcd的 首先,gcd(x,y)= gcd(x,y-x) 并且很容易推广到n个数,所以我们可以把原数 ...

  9. Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...

随机推荐

  1. [Openwrt 扩展下篇] Openwrt搭建私有云Owncloud 9

    网上很多资料讲用Linux打造owncloud构建私有云 ,花了些时间研究了下,我将之前的需求打造成了Openwrt下的Owncloud 9.其实网上还有Seafile.大家对比来看下知乎的评论,其实 ...

  2. 谈谈.NET MVC QMVC高级开发

    自从吾修主页上发布了QMVC1.0,非常感兴趣,用了半月的时间学习,真的感觉收益非浅,在此声明非常感谢吾修大哥的分享! 1.轻快简单,框架就几个类,简单,当然代码少也就运行快!单纯的MVC,使的如果你 ...

  3. gitHub 迁移到gitlab上

    GitHub 迁移到 GitLab 上 第一步在github上生成 token 地址 https://blog.csdn.net/u014175572/article/details/55510825 ...

  4. jQuery简单介绍

    一.jQuery介绍 jQuery是一个轻量级的.兼容多浏览器的JavaScript库. jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方便地进行Ajax交 ...

  5. 【web开发】web前端开发常用技术总结归纳

    技术选型规范规范 • Vue版本:2.x • 前端路由:vue-route • 异步请求:Axios • 全局状态管理:VueX • css预处理器:sass/less • h5项目移动端适配规则:使 ...

  6. InnoDB锁问题

    InnoDB锁问题 InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我 ...

  7. 激活Win10内置版Linux (ubuntu)

    微软自从14316版本后,就开始原生支持Linux  Bash命令行. 1.首先到系统设置——更新和安全——针对开发人员——选择开发者模式. 2.控制面板→程序和功能→启用或关闭Windows功能,勾 ...

  8. 记一次对 Laravel-permission 项目的性能优化

    我最近研究分析了在 SWIS上面创建的项目的性能.令人惊讶的是,最耗费性能的方法之一是优秀的  spatie/laravel-permission 包造成的. 经过查阅更多资料和研究,发现一个可能明显 ...

  9. qt 问题及处理

    1. 包依赖问题 在windows平台时,通过microsoft process Explorer可以查看所以来的dll.并将这些dll复制到应用程序目录,加上qt.conf就可以使用了. [Path ...

  10. java对象与xml相互转换工具类

    public class XmlHelper { /** * Object转XML * * @param object * @return * @throws Exception */ public ...