codeforces 777E dp+线段树+离散化

对于一组(a,b,h),寻找一个满足条件的排列:a[i+1]< b[i] <=b[i+1],使得∑h尽量大。
考虑动态规划,将数组按照b的大小排列,然后从上往下枚举圆环放在最下面。dp[i][j]=max{dp[i-1][k]}+h[i],其中k>a[i],j表示最下面的圆环的外直径,dp表示高度。考虑到数值在10^9范围内,需要离散化数据。考虑到需要频繁地求范围内最大值,考虑用线段树维护。
比较容易错的点:
1.排序的时候b相等的话还要按照a的大小排序,因为有可能有先用一个内环比较小的套在底下,再放一个内环比较大、外环一样大的。
2.由于题意特殊,只需要单点更新并查询(a,N]的最大值,不需要传统线段树那样递归,一个循环就能跑出来。前提是建完全二叉树。
3.数据大,注意除了dp数组以外结构体也需要开到longlong,最后输出的时候要%I64d。

#include<stdio.h>
#include<algorithm>
#include<map>
using namespace std;
const int n=131072;
int T,X[n*3],ind=0,jnd=0,M[n*2];
long long dp[n*4];
struct node{
    int a,b;
    long long k;
    bool operator <(const node& B){
        return b==B.b?a<B.a:b<B.b;
    }
    void read(){
        a=lower_bound(M,M+ind,X[jnd++])-M;
        b=lower_bound(M,M+ind,X[jnd++])-M;
        k=X[jnd++];
    }
}p[n];
long long getmax(int t){
    t+=n*2-1;
    long long res=dp[t];
    do{
        if(!(t&1))if(res<dp[t|1])res=dp[t|1];
    }while(t>>=1);
    return res;
}
void verify(int x,long long y){
    int t=n*2+x-1;
    dp[t]=y;
    while(t>>=1){
        dp[t]=max(dp[t<<1],dp[t<<1|1]);
    }
}
int main(){
    scanf("%d",&T);
    for(int i=0;i<3*T;i++){
        scanf("%d",X+i);
        if(i%3!=2)M[ind++]=X[i];
    }
    sort(M,M+ind);
    for(int i=0;i<T;i++)
        p[i].read();
    sort(p,p+T);
    long long temp;
    for(int i=0;i<T;i++){
        temp=getmax(p[i].a+1)+p[i].k;
        if(dp[p[i].b+2*n-1]<temp)verify(p[i].b,temp);
    }
    printf("%I64d",dp[1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值