本来并不打算出原创题的,此题集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. jQuery DataTables插件分页允许输入页码跳转

    背景说明 项目中使用jQuery DataTables插件来实现分页表格,但是默认的分页样式不能输入页码进行跳转,在页数非常多的时候使用很不方便,最主要的还是没有达到产品部门的设计要求,所以我需要寻找 ...

  2. 2018.09.07 Amount of degrees(数位dp)

    描述 求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的B的整数次幂之和. 例如,设X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意: 17 = 24+20, ...

  3. 2018.07.09 顺序对齐(线性dp)

    顺序对齐 题目描述 考虑两个字符串右对齐的最佳解法.例如,有一个右对齐方案中字符串是 AADDEFGGHC 和 ADCDEGH. AAD~DEFGGHC ADCDE~~GH~ 每一个数值匹配的位置值 ...

  4. Linux Vim替换字符串的一些方法小结

    使用Linux环境 进行开发工作的程序猿经常有编辑器之争,是vim牛还是emacs棒.二者都是程序猿的开发神器,不管用好哪一个都会使你的工作事半功倍. 本文重点介绍 Vim的替换字符串方法技巧,这些方 ...

  5. Fiddler调式使用(一)深入研究[转载]

    Fiddler调式使用(一)深入研究 阅读目录 Fiddler的基本概念 如何安装Fiddler 了解下Fiddler用户界面 理解不同图标和颜色的含义 web session的常用的快捷键 了解we ...

  6. js获取年月日时分秒星期

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. LA 4670 Dominating Patterns (AC自动机)

    题意:给定n个字符串和一个文本串,查找哪个字符串出现的次数的最多. 析:一匹配多,很明显是AC自动机.只需要对原来的进行修改一下,就可以得到这个题的答案, 计算过程中,要更新次数,并且要映射字符串.如 ...

  8. authentication 和 authorization

    单词 词性 解释 authentication n. 认证 authentic adj. 真实的 authorization n. 授权 authorise vt. 授权 authentication ...

  9. faceswap安装说明

    Installing Faceswap Installing Faceswap Prerequisites Hardware Requirements Supported operating syst ...

  10. C++中的inline声明

    C++中的inline声明 1. inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把函数指定为内联函数. inline int min(i ...