LOJ#3034. 「JOISC 2019 Day2」两道料理

找出最大的\(y_{i}\)使得\(sumA_{i} + sumB_{y_i} \leq S_{i}\)

和最大的\(x_{j}\)使得\(sumA_{x_{j}} + sumB_{j} \leq T_{j}\)

然后我们相当于从\((0,0)\)走到\((n,m)\)一条路径,如果\(i,y_{i}\)在路径上或路径上方,那么就加上\(P_{i}\),如果\(x_{j},j\)在路径上或路径下方,就加上\(Q_{j}\)

我们加上所有的\(P_{i}\),然后把第一种点改成\(i - 1,y_{i} + 1\),如果这种点在路径上或路径下面,我们会有\(-P_{i}\)的贡献,于是就变成了走一条路径使得路径下方的点值最大

我们在每次拐弯的时候加上这一列的值,最后还要加上\(sum_{n,m}\)

\(sum_{i,j}\)表示这个点在\(i,j\)下面的点的权值和,正下方

\(f_{i,j} = max(f_{i,j - 1},f_{i - 1,j}, + sum_{i - 1,j })\)

考虑用线段树维护整个dp数组,我们相当于从后往前遍历这一列的所有点,并维护前缀最大值的差分,如果它后面的正数能使加入一个负数的值被消掉就加,否则就把后面都改成0,如果是加一个正数就是直接加了

参考的zusuyu题解qwq

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 1000005
#define ba 47
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 +c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
int64 sa[MAXN],sb[MAXN],a[MAXN],b[MAXN],p[MAXN],q[MAXN],s[MAXN],t[MAXN],ans;
vector<pair<int,int64> > v[MAXN];
struct node {
int l,r;int64 sum;bool cov;
}tr[MAXN * 4];
void cover(int u) {
tr[u].sum = 0;tr[u].cov = 1;
}
void update(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u) {
if(tr[u].cov) {
cover(u << 1);
cover(u << 1 | 1);
tr[u].cov = 0;
}
}
void build(int u,int l,int r) {
tr[u].l = l;tr[u].r = r;tr[u].sum = 0;tr[u].cov = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
}
void Cover(int u,int l,int r) {
if(tr[u].l == l && tr[u].r == r) {cover(u);return;}
int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u);
if(r <= mid) Cover(u << 1,l,r);
else if(l > mid) Cover(u << 1 | 1,l,r);
else {Cover(u << 1,l,mid);Cover(u << 1 | 1,mid + 1,r);}
update(u);
}
int64 Query(int u,int l,int r) {
if(tr[u].l == l && tr[u].r == r) {
return tr[u].sum;
}
int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u);
if(r <= mid) return Query(u << 1,l,r);
else if(l > mid) return Query(u << 1 | 1,l,r);
else return Query(u << 1,l,mid) + Query(u << 1 | 1,mid + 1,r);
}
void Add(int u,int pos,int64 v) {
if(tr[u].l == tr[u].r) {tr[u].sum += v;return;}
int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u);
if(pos <= mid) Add(u << 1,pos,v);
else Add(u << 1 | 1,pos,v);
update(u);
}
int64 Change(int u,int l,int r,int64 v) {
if(tr[u].l == l && tr[u].r == r) {
if(tr[u].sum <= v) {
int x = tr[u].sum;
cover(u);
return x;
} if(tr[u].l == tr[u].r) {tr[u].sum -= v;return v;}
else {
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
int64 t = Change(u << 1,l,mid,v);
if(v - t) t += Change(u << 1 | 1,mid + 1,r,v - t);
update(u);
return t;
} }
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(r <= mid) {
int64 x = Change(u << 1,l,r,v);
update(u);return x;
}
else if(l > mid) {
int64 x = Change(u << 1 | 1,l,r,v);
update(u);return x;
}
else {
int64 x = Change(u << 1,l,mid,v);
if(v - x) x += Change(u << 1 | 1,mid + 1,r,v - x);
update(u);return x;
}
}
void Process(int pos,int64 v) {
if(pos > M) return;
if(v >= 0) Add(1,pos,v);
else {
int64 x = Query(1,pos,M);
if(v + x <= 0) Cover(1,pos,M);
else Change(1,pos,M,-v);
}
}
void Solve() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) {
read(a[i]);read(s[i]);read(p[i]);
sa[i] = sa[i - 1] + a[i];
}
for(int i = 1 ; i <= M ; ++i) {
read(b[i]);read(t[i]);read(q[i]);
sb[i] = sb[i - 1] + b[i];
}
for(int i = 1 ; i <= N ; ++i) {
int y = upper_bound(sb + 1,sb + M + 1,s[i] - sa[i]) - sb - 1;
if(sa[i] <= s[i]) {
if(y + 1 <= M) v[i - 1].pb(mp(y + 1,-p[i]));
//out(i - 1);space;out(y + 1);enter;
ans += p[i];
}
}
for(int i = 1 ; i <= M ; ++i) {
int x = upper_bound(sa + 1,sa + N + 1,t[i] - sb[i]) - sa - 1;
if(sb[i] <= t[i]) {
v[x].pb(mp(i,q[i]));
//out(x);space;out(i);enter;
}
}
build(1,0,M);
for(int i = 0 ; i < N ; ++i) {
sort(v[i].begin(),v[i].end(),[](pair<int,int64> a,pair<int,int64> b) {return a.fi > b.fi;});
int pre = M + 1;int64 val = 0;
for(auto t : v[i]) {
if(t.fi != pre) {
Process(pre,val);
pre = t.fi;val = 0;
}
val += t.se;
}
Process(pre,val); }
ans += tr[1].sum;
for(auto t : v[N]) ans += t.se;
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

【LOJ】#3034. 「JOISC 2019 Day2」两道料理的更多相关文章

  1. 【LOJ】#3033. 「JOISC 2019 Day2」两个天线

    LOJ#3033. 「JOISC 2019 Day2」两个天线 用后面的天线更新前面的天线,线段树上存历史版本的最大值 也就是线段树需要维护历史版本的最大值,后面的天线的标记中最大的那个和最小的那个, ...

  2. LOJ#2882. 「JOISC 2014 Day4」两个人的星座(计算几何)

    题面 传送门 题解 我们发现如果两个三角形相离,那么这两个三角形一定存在两条公切线 那么我们可以\(O(n^2)\)枚举其中一条公切线,然后可以暴力\(O(n^3)\)计算 怎么优化呢?我们可以枚举一 ...

  3. @loj - 3039@ 「JOISC 2019 Day4」蛋糕拼接 3

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 今天是 IOI 酱的生日,所以她的哥哥 JOI 君给她预定了一个 ...

  4. LOJ #2877. 「JOISC 2014 Day2」交朋友 并查集+BFS

    这种图论问题都挺考验小思维的. 首先,我们把从 $x$ 连出去两条边的都合并了. 然后再去合并从 $x$ 连出去一条原有边与一条新边的情况. 第一种情况直接枚举就行,第二种情况来一个多源 bfs 即可 ...

  5. LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA

    非常好的一道图论问题. 显然,我们要求城市间的最小生成树,然后查询路径最大值. 然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围. 显然,如果两个城市的管辖范围没有交集的话 ...

  6. [LOJ#2878]. 「JOISC 2014 Day2」邮戳拉力赛[括号序列dp]

    题意 题目链接 分析 如果走到了下行车站就一定会在前面的某个车站走回上行车站,可以看成是一对括号. 我们要求的就是 类似 代价最小的括号序列匹配问题,定义 f(i,j) 表示到 i 有 j 个左括号没 ...

  7. 【LOJ】#3036. 「JOISC 2019 Day3」指定城市

    LOJ#3036. 「JOISC 2019 Day3」指定城市 一个点的可以dp出来 两个点也可以dp出来 后面的就是在两个点的情况下选一条最长的链加进去,用线段树维护即可 #include < ...

  8. 【LOJ】#3031. 「JOISC 2019 Day1」聚会

    LOJ#3031. 「JOISC 2019 Day1」聚会 听说随机可过? 我想了很久想了一个不会被卡的做法,建出前\(u - 1\)个点的虚树,然后找第\(u\)个点的插入位置,就是每次找一条最长链 ...

  9. 【LOJ】#3030. 「JOISC 2019 Day1」考试

    LOJ#3030. 「JOISC 2019 Day1」考试 看起来求一个奇怪图形(两条和坐标轴平行的线被切掉了一个角)内包括的点个数 too naive! 首先熟练的转化求不被这个图形包含的个数 -- ...

随机推荐

  1. CodeForces 754C Vladik and chat ——(xjbg)

    虽然是xjbg的题目,但是并不很好做. 题意不难理解.读入有点麻烦.做法是先正着推每段对话的?可能是谁说的,然后反过来选择即可.正推时,其中vis数组表示谁已经被用过了,cnt表示该组当前可以选择几个 ...

  2. centos7下面安装tomcat

    前言 对于一个新安装的 centos 系统来说,是没有 tomcat 服务器的.用下面的命令可以查看 tomcat 服务的状态. systemctl status tomcat.service//或者 ...

  3. IDEA个人常用配置记录

    原文 一.常用快捷键 编辑 ⇧ + ↩:开始新的一行 ⌘ + ⇧ + ↩:行内任意位置进行换行,并自动补齐“;”.“{}” ⌘ + ⇧ + U:大小写切换 ⌥ + ⌦:删除到单词的末尾(⌦键为Fn+D ...

  4. Linux设备驱动程序 之 自旋锁

    概念 自旋锁可以再不能休眠的代码中使用,比如中断处理例程:在正确使用的情况下,自旋锁通常可以提供比信号量更高的性能: 一个自旋锁是一个互斥设备,它只能由两个值,锁定和解锁:通常实现为某个整数值中的单个 ...

  5. 报错1251 - Client does not support authentication protocol 解决办法

    # 1.容器中登录mysql,查看mysql的版本 status; # 2,进行授权远程连接(注意mysql 8.0跟之前的授权方式不同) GRANT ALL ON *.* TO 'root'@'%' ...

  6. 2965 -- The Pilots Brothers' refrigerator

    The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 27893 ...

  7. 性能分析 | Linux 内存占用分析

    这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令:查看/proc/[pid]/下的文件.文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/ ...

  8. 前端知识点回顾——Nodejs

    Node.js 事件循环机制 setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行setImmediate指定的回调函数,和setTimeout(fn,0 ...

  9. ios 报错记录

    1. 运行xcode 报错:unterminated conditional directive #ifdef 缺少对应的#endif 在结尾加上就好了 2.iOS添加非(c,c++)文件引发的&qu ...

  10. 【JavaScript】全面解析offsetLeft、offsetTop

    假设 obj 为某个 HTML 控件.obj.offsetLeft 指 obj 距离左方或上层控件的位置,整型,单位像素. obj.offsetRight 指 obj 距离右方或上层控件的位置,整型, ...