[CSP-S模拟测试]:数对(线段树优化DP)
2024-09-02 22:53:01
题目传送门(内部题96)
输入格式
第一行一个整数$n$,接下来$n$行每行三个整数$a_i,b_i,w_i$。
输出格式
一行一个整数表示最大权值和。
样例
样例输入:
5
4 4 1
2 3 3
1 5 1
4 2 2
5 2 3
样例输出:
7
数据范围与提示
对于$10\%$的数据,$n\leqslant 8$。
对于$40\%$的数据,$n\leqslant 200$。
对于$70\%$的数据,$n\leqslant 3,000$。
对于$100\%$的数据,$1\leqslant n\leqslant 10^5 ,1\leqslant a_i,b_i,w_i\leqslant 10^9$。
题解
先来考虑如何选择最优,按$a_i+b_i$从小到大排序和按$min(a_i,b_i)$从小到大排序都能通过此题(我也不知道为什么)。
发现$a_i,b_i$只与其大小有关,而与其具体值无关,所以直接离散化就好了。
考虑$DP$,定义$dp[i][j]$表示选到第$i$个,$\min(a_i)$为$j$的最大贡献。
可以写出转移:
$$dp[i][j]=\max(dp[i-1][j])$$
$$dp[i][\max(j,a[i])]=\max(dp[i-1][j]+w[i])$$
显然无论是空间还是时间都不能容忍,考虑优化。
发现其实就是一个区间加的过程,于是可以用线段树优化。
时间复杂度:$\Theta(n\log cnt)$(其中$cnt$为不同的$a_i$和$b_i$的种数)。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
unordered_map<int,int>mp;
struct rec{int a,b,w;}e[100001];
int n;
int cnt;
int que[200001];
long long tr[1000000],lz[1000000];
bool cmp(rec a,rec b){return a.a+a.b<b.a+b.b;}
void pushup(int x){tr[x]=max(tr[L(x)],tr[R(x)]);}
void pushdown(int x)
{
tr[L(x)]+=lz[x];
tr[R(x)]+=lz[x];
lz[L(x)]+=lz[x];
lz[R(x)]+=lz[x];
lz[x]=0;
}
void add(int x,int l,int r,int L,int R,int w)
{
if(r<L||R<l)return;
if(L<=l&&r<=R)
{
tr[x]+=w;
lz[x]+=w;
return;
}
int mid=(l+r)>>1;
pushdown(x);
add(L(x),l,mid,L,R,w);
add(R(x),mid+1,r,L,R,w);
pushup(x);
}
void upd(int x,int l,int r,int k,long long w)
{
if(l==r)
{
tr[x]=max(tr[x],w);
return;
}
int mid=(l+r)>>1;pushdown(x);
if(k<=mid)upd(L(x),l,mid,k,w);
else upd(R(x),mid+1,r,k,w);
pushup(x);
}
long long ask(int x,int l,int r,int L,int R)
{
if(r<L||R<l)return -0x3f3f3f3f3f3f3f3f;
if(L<=l&&r<=R)return tr[x];
int mid=(l+r)>>1;pushdown(x);
return max(ask(L(x),l,mid,L,R),ask(R(x),mid+1,r,L,R));
}
int main()
{
scanf("%lld",&n);int top=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].w);
que[++top]=e[i].a;que[++top]=e[i].b;
}
sort(que+1,que+top+1);
for(int i=1;i<=top;i++)if(que[i]!=que[i-1])mp[que[i]]=++cnt;
for(int i=1;i<=n;i++){e[i].a=mp[e[i].a];e[i].b=mp[e[i].b];}
sort(e+1,e+n+1,cmp);
for(int i=1;i<=n;i++)
{
long long flag=ask(1,1,cnt,1,min(e[i].a,e[i].b));
add(1,1,cnt,e[i].a,e[i].b,e[i].w);
upd(1,1,cnt,e[i].a,flag+e[i].w);
}
printf("%lld",tr[1]);
return 0;
}
rp++
最新文章
- Warm myself by my hand
- gulp删除文件和文件夹
- 用ADMM求解大型机器学习问题
- php服务端写日志文件
- 手机操控全站仪安卓版 测量员.app
- wikioi 1098 均分纸牌
- VMware EXSI 6.0 体验
- 批量扫描互联网无线路由设备telnet,并获取WIFI密码
- Python Socket,How to Create Socket Cilent? - 网络编程实例
- TCP/IP协议原理与应用笔记13:底层网络技术之传输介质
- DORIS-软件网址
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
- RTMPdump 使用说明
- git合并分支
- C# 按不同的字节编码,通过字节数去截取字符串
- update_engine-整体结构(三)
- Object...与Object[]使用的一点区别和记录
- (原)visual studio 2015中添加dll路径
- JVM 字节码(四)静态方法、构造代码、this 以及 synchronized 关键字
- 10-51单片机ESP8266学习-AT指令(ESP8266连接路由器,建立TCP服务器,分别和C#TCP客户端和AndroidTCP客户端通信+花生壳远程通信)
热门文章
- P1216数字三角形
- laravel5.5入门-安装和认证
- js中index()的四种经典用法(转https://blog.csdn.net/superit401/article/details/51726826)
- echarts图标使用(一)
- 06、CEL文件与灰度图像
- npm学习(八)之如何使用语义化版本
- uoj #450[集训队作业2018]复读机
- decode与case when 函数
- 响应式前端框架Bootstrap系列(11)分页
- spring boot引入thymeleaf导致中文乱码