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

首先先看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. rsync同步文件(多台机器同步代码...)

    常用组合   rsync -av --delete-after --exclude-from="a.txt"  x/x -e ssh x:/x/x   a.txt 制定忽略的文件, ...

  2. CSS 实现单边阴影

    box-shadow: 0px -15px 10px -15px #111; 五个值分别为:x y blur spread color 将 spread 设置成 blur 的负值即可 这种只适用于 o ...

  3. 2016.6.24——vector<vector<int>>【Binary Tree Level Order Traversal】

    Binary Tree Level Order Traversal 本题收获: 1.vector<vector<int>>的用法 vector<vector<int ...

  4. JS事件用法

    1.常用事件理解

  5. 【四校联考】【比赛题解】FJ NOIP 四校联考 2017 Round 7

    此次比赛为厦门一中出题.都是聚劳,不敢恭维. 莫名爆了个0,究其原因,竟然是快读炸了……很狗,很难受. 话不多说,来看看题: [T1] 题意: 样例: PS:1<=h[i]<=100000 ...

  6. Python基础三(选择,循环)

    序 首先我们知道程序的执行有三种结构:顺序.选择.循环三种结构,而为了方便我们书写和多次利用我们就需要把一段代码封装器来,这就是方法.今天我就说的是程序的基本结构的格式和方法. 注:所有的程序都可以通 ...

  7. 20155225 实验一《Java开发环境的熟悉》实验报告

    20155225 实验一<Java开发环境的熟悉>实验报告 一.命令行下Java程序的开发 按照老师提供的步骤,运行程序如下: 二.IDEA下Java程序开发.调试 设置条件断点如下: 三 ...

  8. OA项目CRUD和单元测试(一)

    使用ModeFirst方法生成数据库,EntityFramework5.0. 一:Model层的模型:(根据模型生成数据库) 二:Dal层的UserInfo代码: namespace SunOA.EF ...

  9. .NETCore Sqlserver下对Dapper的扩展支持

    这里我们自定义一个IServiceCollection的扩展,例如下面我的扩展 services.AddDapperContext(dapperoptions => { dapperoption ...

  10. C#中ASCII码与字符串的互换

    主要代码: int a = (int)'a';// 把字符直接转换为int类型,即可得到ASCII码值 ).ToString();// 将数字直接转换为char类型,即可得到ASCII码对应的字符 C ...