2018CCPC网络赛-线段树求区间最值+离散化+dp
转自:HDU6447 YJJ's Salesman-2018CCPC网络赛-线段树求区间最值+离散化+dp
Problem:Portal传送门
原题目描述在最下面。
1e5个点,问从(0,0)走到(1e9,1e9)的最大收益。
当你从(u-1,v-1)走到(u,v)时,你可以获得点(u,v)的权值。
solution:
十分详细了。
直接线段树区间最值。当然也可以树状数组,不能st表。
dp[i]=max(query_max(0,dp[i]−1,1)+val[i],dp[i])dp[i]=max(query_max(0,dp[i]−1,1)+val[i],dp[i])
update(i,dp[i],1)update(i,dp[i],1)
记得离散化再排序,先x从小到大,再y从大到小,每次更行一行。
按01背包的更新顺序,滚动数组优化为一维。
细节见代码。
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define mme(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef unsigned long long LL;
const int N = 2e5 + 7;
const int M = 1e5 + 7;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int ar[N],br[N];//离散化
int dp[N];
struct lh //储存1e5个点
{
int x,y,v;
} op[N];
bool cmp(lh &a,lh &b)
{
if(a.x!=b.x)return a.x<b.x;
return a.y>b.y;
}
int n;
/**********线段树区间最值**********/
struct lp
{
int l, r, sum;
} cw[N<<2];
void push_up(int rt)
{
cw[rt].sum = max(cw[lson].sum, cw[rson].sum);
}
void build(int l,int r,int rt)
{
cw[rt].l = l;
cw[rt].r = r;
cw[rt].sum = 0;
if(l==r)
{
return;
}
int m = (l+r)/2;
build(l,m,lson);
build(m+1,r,rson);
push_up(rt);
}
void update(int p,int c,int rt)
{
int l = cw[rt].l;
int r = cw[rt].r;
int m = (l+r)/2;
if(l==r)
{
cw[rt].sum = c;
return;
}
if(p<=m)update(p,c,lson);
else update(p,c,rson);
push_up(rt);
}
int query(int L,int R,int rt)
{
int l = cw[rt].l;
int r = cw[rt].r;
int m = (l+r)/2;
if(L<=l&&r<=R)
{
return cw[rt].sum;
}
if(L>m)return query(L,R,rson);
else if(R<=m)return query(L,R,lson);
return max(query(L,m,lson),query(m+1,R,rson));
}
/****************/
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
scanf("%d%d%d",&op[i].x,&op[i].y,&op[i].v);
ar[i] = op[i].x;
br[i]=op[i].y;
}
int p = n + 1;
ar[n] = 0;
br[n] = 0;
sort(ar,ar+p);
sort(br,br+p);
int a = unique(ar,ar+p)-ar;
int b = unique(br,br+p)-br;
for(int i = 0; i < n; ++i)
{
op[i].x=lower_bound(ar,ar+a,op[i].x)-ar;
op[i].y=lower_bound(br,br+b,op[i].y)-br;
}
//以上离散化
sort(op,op+n,cmp);
build(0, b, 1);
mme(dp, 0);
for(int i = 0; i < n; ++i)
{
int flag = op[i].x, j;
for(j = i; j < n; ++j)
{
if(op[j].x != flag)
{
break;
}
int tmp = query(0, op[j].y-1, 1) + op[j].v;
if(tmp > dp[op[j].y])
{
dp[op[j].y] = tmp;
update(op[j].y, dp[op[j].y], 1);
}
}
i = j - 1;
}
int ans = 0;
for(int i = 0; i <= b; ++i)
{
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}
return 0;
}