本来并不打算出原创题的,此题集CF542A和sk的灵感而成,算个半原创吧。

题目大意:

给定有$n$个元素的集合$P$,其中第$i$个元素中包含$L_i,R_i,V_i$三个值。

给定另一个有$n$个元素的集合$Q$,其中第$i$个元素包含$A_i,B_i,C_i$三个值。

选择集合$P$中第$x$个元素和集合$Q$中第$y$个元素的收益为$(r-l+1)*V_x*C_y$,其中$[l,r]$为$[L_i,R_i]$和$[A_i,B_i]$的交集。你需要在集合$P$,$Q$中分别选出一个元素,使得收益最大

数据范围:

子任务一:满足$n≤5000$

子任务二:满足$V_i=1$。

子任务三:满足$L_i=A_i=1$。

子任务四:满足$n≤10^5$

对于全部数据,所有数$≤10^5$,且$L_i≤R_i,A_i≤B_i$。

子任务一:暴力

子任务二:该子任务为CF542A:

这里有一个题解,看情况三和情况四就行了

子任务三:

不难发现该情况下,对于任意的$i,j$必有$L_i≤A_j,B_j≤R_i$,或者$A_j≤L_i,R_i≤B_j$。

我们把$P$和$Q$中所有元素都丢入一个数组中按右端点排序,同时我们种一棵线段树。

若当前元素原先在$P$中,我们用$(R_i-L_i+1)\times V_i$更新第$L_i$个位置的值(取max)

否则,我们查询区间$[A_i,B_i]$中的最大值,将该值乘上$C_i$后更新答案。

不难发现此方法可以处理所有$Q_i$包含$P_j$的情况。

对于$P_i$包含$Q_j$的情况,我们交换下两个集合再处理一次就好了。

子任务四:

首先要处理一下$P_i$包含$Q_i$或者$Q_i$包含$P_i$的情况,直接用子任务三的方式处理一下就行了。

我们将$P$中第$i$个元素看成一个定义域在$[L_i,R_i]$间的函数,我们把这个函数写作$F_i(x)$。

不难发现$F_i(x)=V_ix-(L_i-1)\times V_i$。

为了方便接下来的表述,我们将$F_i(x)$更改为如下形式:

$F_i(x)=\begin{cases} V_ix-(L_i-1)\times V_i \ \ \ x\in[L_i,R_i] \\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ x\notin[L_i,R_i]\end{cases}$

这是个分段函数

我们在$Q$中找出第y个元素$Q_y$,若存在$i$满足$A_y≤L_i$,则$Q_y$与$P_i$产生的收益为$C_y\times F_i(B_y)$。

最终答案显然为$max(C_y\times F_i(B_y))$。

按照子任务三的套路,我们把$P$和$Q$中所有元素都丢入一个数组中按左端点排序,维护一个保存函数的集合$S$

定义$S(x)=max_{F∈S}F(x)$

我们从大到小从数组中取出元素

若当前元素原先在$P$中,我们求出该元素对应的函数,并把它丢入$S$中。

否则,我们用$C_i\times S(B_i)$更新答案。

该做法复杂度显然是$O(nT_s)$,其中$T_s$表示求$S(x)$的复杂度。

我们不难想到$T_s=O(n)$的做法,但是不够优美。

我们考虑种一棵线段树,线段树的每个节点分别维护一个支持插入函数的半平面交。

如果我们要加入一个定义域在$[l,r]$的一次函数$f(x)$,就在线段树对应的区间上插入这个函数即可。

对于$S(x)$操作,我们只需要找出所有包含$x$的区间,在这些区间上的半平面交上求值即可。

单次插入的复杂度均摊为$O(log^2\ n)$ 单次查询的复杂度为$O(log^2\ n)$。

然而该方法只能处理出$Q_i$在$P_j$左边的情况。$Q_i$在$P_j$右边的情况我们交换一下两个集合再跑一遍就行了。

所以这是一道扫描线+线段树维护动态半平面的题目

总复杂度就是$O(n\ log^2\  n)$,空间复杂度$O(n\ log\ n)$。

完结撒花

 #include<bits/stdc++.h>
#define M 100010
#define L long long
#define mid ((aa[x].l+aa[x].r)>>1)
#define S set<line>::iterator
using namespace std; int n,N=,up=; L ans=;
struct lr{
int l,r,val;
void rd(){scanf("%d%d%d",&l,&r,&val); up=max(up,r);}
}a[M],b[M];
void swapAB(){for(int i=;i<=n;i++) swap(a[i],b[i]);}
struct ask{
int id,isa; ask(){id=isa=;}
ask(int ID,int ISa){id=ID; isa=ISa;}
friend bool operator <(ask A,ask B){
int vala=A.isa?a[A.id].l:b[A.id].l;
int valb=B.isa?a[B.id].l:b[B.id].l;
if(vala!=valb) return vala<valb;
return A.isa>B.isa;
}
}p[M*]; namespace SolveContains{
struct seg{int l,r;L maxn;}aa[<<];
void build(int x,int l,int r){
aa[x].l=l; aa[x].r=r; aa[x].maxn=; if(l==r) return;
build(x<<,l,mid); build(x<<|,mid+,r);
}
void updata(int x,int k,L val){
aa[x].maxn=max(aa[x].maxn,val);
if(aa[x].l==aa[x].r) return;
if(k<=mid) updata(x<<,k,val);
else updata(x<<|,k,val);
}
L query(int x,int l,int r){
if(l<=aa[x].l&&aa[x].r<=r) return aa[x].maxn;
L res=;
if(l<=mid) res=max(res,query(x<<,l,r));
if(mid<r) res=max(res,query(x<<|,l,r));
return res;
}
bool cmp(ask A,ask B){
int vala=A.isa?a[A.id].r:b[A.id].r;
int valb=B.isa?a[B.id].r:b[B.id].r;
if(vala!=valb) return vala<valb;
return A.isa<B.isa;
}
void sub(){
build(,,up);
N=; for(int i=;i<=n;i++) p[++N]=ask(i,),p[++N]=ask(i,);
sort(p+,p+N+,cmp);
for(int i=;i<=N;i++){
int id=p[i].id;
if(p[i].isa){
L now=query(,a[id].l,a[id].r);
ans=max(ans,now*a[id].val);
}else{
L val=1LL*b[id].val*(b[id].r-b[id].l+);
updata(,b[id].l,val);
}
}
}
void solve(){sub();swapAB();sub();swapAB();}
} void ReadData(){
cin>>n;
for(int i=;i<=n;i++) a[i].rd();
for(int i=;i<=n;i++) b[i].rd();
} struct line{
L k,b; line(){k=b=;}
line(L _k,L _b){b=_b; k=_k;}
L f(L x){return k*x+b;}
friend bool operator <(line a,line b){
if(a.k==b.k) return a.b<b.b;
return a.k<b.k;
}
friend double operator *(line a,line b){
return .*(b.b-a.b)/(a.k-b.k);
}
};
bool under(line a,line b,line c){
double x=a*b;
if(a.f(x)>=c.f(x)) return ;
return ;
}
struct plane{//半平面
set<line> s;
map<double,line> mp;
void clear(){
s.clear(); mp.clear();
s.insert(line(,));
mp[-]=line(,);
}
L f(int x){
map<double,line>::iterator it=mp.upper_bound(x); it--;
line now=it->second;
return now.f(x);
}
void remove(S it){
S nxt=it,pre=it; nxt++; pre--;
if(nxt!=s.end()){
double l=(*it)*(*nxt);
mp.erase(mp.find(l));
double x=(*nxt)*(*pre);
mp[x]=*nxt;
}
double r=(*it)*(*pre);
mp.erase(mp.find(r));
s.erase(it);
}
void insert(line l){
S nxt=s.upper_bound(l),pre=nxt; pre--;
if(nxt!=s.end()){
double x=(*nxt)*(*pre);
mp.erase(mp.find(x));
double r=l*(*nxt);
mp[r]=(*nxt);
}
double x=l*(*pre);
s.insert(l); mp[x]=l;
}
void add(line l){
S it=s.upper_bound(l),nx=it,ls=it,hh; ls--;
if(it!=s.end()&&under(*it,*ls,l)) return;
for(nx++;it!=s.end()&&nx!=s.end();it=nx,nx++){
double x=(*it)*(*nx);
line now=*it;
if(now.k==l.k) return;
if(l.f(x)>=now.f(x)) remove(it);
else break;
}
it=s.upper_bound(l); it--; ls=it;
for(ls--;it!=s.begin();){
double x=(*it)*(*ls);
line now=(*it);
if(now.k==l.k||l.f(x)>=now.f(x)){
hh=it; hh--; ls--;
remove(it);
it=hh;
}
else break;
}
insert(l);
}
}; namespace seg{
struct hhh{
int l,r; plane p;
void insert(line now){return p.add(now);}
L f(L x){return p.f(x);}
}aa[<<]; void build(int x,int l,int r){
aa[x].l=l; aa[x].r=r; aa[x].p.clear();
if(l==r) return;
build(x<<,l,mid); build(x<<|,mid+,r);
}
void updata(int x,int l,int r,line now){
if(l<=aa[x].l&&aa[x].r<=r) return aa[x].insert(now);
if(l<=mid) updata(x<<,l,r,now);
if(mid<r) updata(x<<|,l,r,now);
}
L query(int x,int k){
L res=aa[x].f(k);
if(aa[x].l==aa[x].r) return res;
if(k<=mid) res=max(res,query(x<<,k));
else res=max(res,query(x<<|,k));
return res;
}
} namespace SolveOthers{
void sub(){
seg::build(,,up);
N=; for(int i=;i<=n;i++) p[++N]=ask(i,),p[++N]=ask(i,);
sort(p+,p+N+);
for(int i=N;i;i--){
int id=p[i].id;
if(p[i].isa){
L now=seg::query(,a[id].r);
ans=max(ans,now*a[id].val);
}else{
line hh=line(b[id].val,-1LL*b[id].val*(b[id].l-));
seg::updata(,b[id].l,b[id].r,hh);
}
}
}
void solve(){sub();swapAB();sub();}
} main(){
ReadData();
SolveContains::solve();
SolveOthers::solve();
cout<<ans<<endl;
}

【xsy3423】党² 线段树+李超线段树or动态半平面交的更多相关文章

  1. 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

    4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][ ...

  2. 【BZOJ-3165】Segment 李超线段树(标记永久化)

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 368  Solved: 148[Submit][Sta ...

  3. 【BZOJ-1568】Blue Mary开公司 李超线段树 (标记永久化)

    1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 557  Solved: 192[Submit ...

  4. Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)

    听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...

  5. 【BZOJ3165】[HEOI2013]Segment(李超线段树)

    [BZOJ3165][HEOI2013]Segment(李超线段树) 题面 BZOJ 洛谷 题解 似乎还是模板题QwQ #include<iostream> #include<cst ...

  6. 【BZOJ1568】[JSOI2008]Blue Mary开公司(李超线段树)

    [BZOJ1568][JSOI2008]Blue Mary开公司(李超线段树) 题面 BZOJ 洛谷 题解 是模板题啊. #include<iostream> #include<cs ...

  7. Luogu P4097 [HEOI2013]Segment 李超线段树

    题目链接 \(Click\) \(Here\) 李超线段树的模板.但是因为我实在太\(Naive\)了,想象不到实现方法. 看代码就能懂的东西,放在这里用于复习. #include <bits/ ...

  8. BZOJ.3938.Robot(李超线段树)

    BZOJ UOJ 以时间\(t\)为横坐标,位置\(p\)为纵坐标建坐标系,那每个机器人就是一条\(0\sim INF\)的折线. 用李超线段树维护最大最小值.对于折线分成若干条线段依次插入即可. 最 ...

  9. BZOJ.4515.[SDOI2016]游戏(树链剖分 李超线段树)

    BZOJ 洛谷 每次在路径上加的数是个一次函数,容易看出是树剖+李超线段树维护函数最小值.所以其实依旧是模板题. 横坐标自然是取个确定的距离标准.取每个点到根节点的距离\(dis[i]\)作为\(i\ ...

随机推荐

  1. Linux下JDK应该安装在哪个位置

    在百度知道上看到的回答觉得不错:https://zhidao.baidu.com/question/1692690545668784588.html 如果你认为jdk是系统提供给你可选的程序,放在op ...

  2. 2018上IEC计算机高级语言(C)作业 第0次作业

    最理想的师生关系是健身教练和学员的关系,在这种师生关系中你期望获得来自老师的哪些帮助? 最理想的的师生关系是健身教练和学员的关系,其实我个人感觉不太认同,我觉得老师和学生之间更多的是一种共生关系,像植 ...

  3. 使用bat批处理文件备份mysql数据库

    @echo offset date_string=%date:~0,4%_%date:~5,2%_%date:~8,2%  //日期set time_string=%time:~0,2%_%time: ...

  4. idea使用svn提交时出现错误Warning not all local changes may be shown due to an error

    参考于https://www.cnblogs.com/zhujiabin/p/6708012.html 解决方案: 1.File > Settings > Version Control ...

  5. python操作数据库-安装

    首先是下载软件: 链接:http://pan.baidu.com/s/1nvp1imX 密码:6i0x 之后就是一系列设置. 安装教程:自行百度就行.需要注意的是设置my.ini时,需要加上这些东西( ...

  6. HDU 3897 Base Station (网络流,最大闭合子图)

    题意:给定n个带权点m条无向带权边,选一个子图,则这个子图的权值为 边权和-点权和,求一个最大的权值. 析:把每条边都看成是一个新点,然后建图,就是一个裸的最大闭合子图. 代码如下: #pragma ...

  7. UVa 12003 Array Transformer (分块)

    题意:给定一个序列,然后有 m 个修改,问你最后的序列是什么,修改是这样的 l r v p 先算出从 l 到 r 这个区间内的 小于 v 的个数k,然后把第 p 个的值改成 k * u / (r - ...

  8. 基于SceneControl单击查询功能的实现

    private void HandleIdentify_MouseDown(object sender, ISceneControlEvents_OnMouseDownEvent e) { this. ...

  9. hibernate的一级缓存问题

    1.证明一级缓存的问题 输出结果: 只发出一条查询语句  第二条查询语句没有执行 因为第一条查询语句缓存的存在 2. 移除缓存: 输出结果: 3.一级缓存的快照 就是对一级缓存的数据备份 保证数据库的 ...

  10. 201521123035-个人作业4——alpha阶段个人总结

    个人总结 在alpha 结束之后, 每位同学写一篇个人博客, 总结自己的alpha 过程: 第一部分 类别 具体技能和面试问题 现在的回答(大三) 语言 最拿手的计算机语言是一?,代码量多少?(偏前端 ...