I-Points Division
原题网站传送门:https://ac.nowcoder.com/acm/contest/881/I
题意:给你n个点,每个点有对应的整数坐标,将这些点划分成两个集合使得没有A集合的一个点在B集合的另一个点的右下方或是右方,下方。
题解:可以构造一个折线,使得所有折现左上角都是集合A中的点,右下角都是集合B中的点,不失一般性,我们可以直接假设折线上的所有节点都是集合B中的,这样的构造方法能够使得题意的条件得到满足。
考虑到所有点的y坐标范围特别大,我们先对y坐标进行离散化
设dp[i]表示折现上x坐标对应的点为第i个节点时,所带来的最大收益。注意这个收益在插入新的节点后是实时更新的!
每次插入一个新节点后,他对之前节点影响为:
则
d
p
[
j
]
=
{
d
p
[
j
]
+
b
i
if
j
<
i
,
y
j
>
y
i
d
p
[
j
]
+
a
i
if
j
<
i
,
y
j
<
y
i
dp[j] =\begin{cases} dp[j]+b_i & \text{if }j<i,y_j>y_i \\ dp[j]+a_i & \text{if }j<i,y_j<y_i \end{cases}
dp[j]={dp[j]+bidp[j]+aiif j<i,yj>yiif j<i,yj<yi
他自身所对应的dp值为:
d
p
[
i
]
=
b
i
+
max
d
p
[
j
]
∣
1
<
=
j
<
i
,
y
j
<
y
i
dp[i]=b_i+ \textbf{max}dp[j]|1<=j<i,y_j<y_i
dp[i]=bi+maxdp[j]∣1<=j<i,yj<yi
注意建立一个虚拟节点0,它的y坐标为0,这样把它放入b集合中,这样就能处理所有元素都在a集合的情况。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <cmath>
#include <vector>
#define maxn 100005
typedef long long ll;
using namespace std;
struct segt
{
int l,r;//y value
ll mx,lazy;
}t[maxn*4];
void push_down(int p)
{
if(t[p].lazy)
{
t[p<<1].mx+=t[p].lazy;
t[p<<1|1].mx+=t[p].lazy;
t[p<<1].lazy+=t[p].lazy;
t[p<<1|1].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
void push_up(int p)
{
t[p].mx=max(t[p<<1].mx,t[p<<1|1].mx);
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
// cout<<p<<endl;
t[p].mx=t[p].lazy=0;
if(l==r)return;
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void add(int p,int l,int r,ll val,int flag)
{
if(l>r)return;
if(l<=t[p].l&&r>=t[p].r)
{
if(flag)t[p].mx=val;
else
{
t[p].mx+=val;
t[p].lazy+=val;
}
return;
}
push_down(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)add(p<<1,l,r,val,flag);
if(r>mid)add(p<<1|1,l,r,val,flag);
push_up(p);
}
ll query(int p,int l,int r)
{
if(l>r)return 0;
if(l<=t[p].l&&r>=t[p].r)return t[p].mx;
push_down(p);
ll mx=0;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)mx=max(mx,query(p<<1,l,r));
if(r>mid)mx=max(mx,query(p<<1|1,l,r));
return mx;
}
struct node
{
ll x,y,a,b;
bool operator <(const node &b)const
{
return x<b.x||x==b.x&&y>b.y;
}
}p[maxn];
ll val[maxn];
int tot;
int main()
{
int n;
while(scanf("%d",&n)==1)
{
tot=n;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld",&p[i].x,&p[i].y,&p[i].a,&p[i].b);
val[i]=p[i].y;
}
sort(val+1,val+1+tot);
tot=unique(val+1,val+1+tot)-val-1;
for(int i=1;i<=n;i++)
p[i].y=lower_bound(val+1,val+1+tot,p[i].y)-val;
sort(p+1,p+1+n);
build(1,0,tot);
for(int i=1;i<=n;i++)
{
add(1,p[i].y,p[i].y,query(1,0,p[i].y)+p[i].b,1);//查询到y
add(1,0,p[i].y-1,p[i].a,0);
add(1,p[i].y+1,tot,p[i].b,0);//增加虚拟节点
// cout<<query(1,1,tot)<<endl;
}
printf("%lld\n",t[1].mx);
}
return 0;
}