Gym 101889F — Fundraising 树状数组+离散化+带权上升子序列

题意:给你一些人,每个人有两个特性和一个价值,如果两个人的特性完全相等则可以合并,否则必须一个人的两个特性必须严格大于另一个人才能合并,问:最终可以的到的最大价值。

 

解题思路:看到别人的博客里面有带权上升子序列,让我想起了最长上升子序列  nlogn 的解法:在数组下标 1—i中最长上升子序列结尾数字最小值(一种贪心)。网址链接:https://blog.csdn.net/qq_37555704/article/details/81479623#2onlogn贪心二分优化

和这道题有一点相似,这道题用树状数组 root 维护的是 以 R 结尾 可以得到最大价值和。

这道题还有一个条件,必须两个特质必须严格大于,我们可以将左端点升序排列,右端点降序(奇妙之处)。

奇妙之处:如果我们按照右端点升序,当我们更新时,就会影响后面的值,就会造成答案错误,如果你感觉疑惑,你可以自己模拟一下。

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=10000019;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;

ll root[100005],Right[100005];

struct node
{
    int l;
    int r;
    ll vlaue;
}peo[100005];

bool cmp(node a,node b)
{
    return a.l==b.l?a.r>b.r:a.l<b.l;
}

///维护的是 以 R 结尾 可以得到最大价值和

void add_root(int i,ll x)
{
    while(i<maxn)
    {
        root[i]=max(x,root[i]);
        i=i+(i&(-i));
    }
    return ;
}

ll find_root(int i)
{
    ll cnt=0;
    while(i)
    {
        cnt=max(cnt,root[i]);
        i=i-(i&(-i));
    }
    return cnt;
}

int main()
{
    memset(root,0,sizeof(root));
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d %lld",&peo[i].l,&peo[i].r,&peo[i].vlaue);
        Right[i]=peo[i].r;          ///记录右端点
    }
    sort(peo+1,peo+1+n,cmp);
    sort(Right+1,Right+1+n);        ///离散化
    int len=unique(Right+1,Right+1+n)-Right-1;
    for(int i=1;i<=n;i++)
    {                               ///合并相同特性的人
        if(i<n&&peo[i].l==peo[i+1].l&&peo[i].r==peo[i+1].r)
        {
            peo[i+1].vlaue+=peo[i].vlaue;
            continue;
        }
        ///pos+1为peo[i]第几大
        int pos=lower_bound(Right+1,Right+1+len,peo[i].r)-Right-1;

        ll cnt=find_root(pos);      ///查询最大值
        add_root(pos+1,cnt+peo[i].vlaue);   ///更新最大值
        ///因为当L相等时,R为降序排列,所以更新时不会影。
    }
    printf("%lld\n",find_root(len));
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值