P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶(线段树上二分)

news/2024/10/21 7:46:50

赛时是想到普通的线段树 + 二分 \(O(q\log^2n)\),预期是 70pts,实际 50pts

后面发现又是在 long long 类型的计算中,1ll 写成了 1,然后爆负数,复杂度就错了,T 了四个点


开题,读起来是一个很套路的题目

要对区间在线修改,区间加、(区间乘?),发现数据很大,那就是线段树、树状数组维护了

思考了一下,答案可以分两部分求解,

一是找到使 youyou 死亡的那一轮,之前轮的贡献可以按题意累加得到,

	LL sum = query(1, 1, n), tot = 0ll, last;int cnt = 0ll; // 实际到第 cnt 轮就死亡 while (tot < W){last = tot;tot = sum * (LL)(1ll << cnt) + last;cnt ++;}ans += (LL)((cnt - 1ll) * n); // 所有点覆盖轮 W -= last;

手算了一下时间复杂度应该是 \(O(x)\) 满足 \(sum\sum\limits_{i = 0}^x 2^i = W\),等比数列求和一下近似 \(O(\log n)\)

我一开始测大样例 2s 内本地跑不出来,以为是写假了(就是写假了 qwq,爆负数),然后卡了好久在那想怎么做到 \(sum\cdot 2^x=W\),白给了很多时间

二是确定为第 i 轮死亡时,想到从左往右覆盖具有单调性,可以把死亡位置二分出来,每次求个前缀和

时间复杂度是 \(O(\log^2n)\)

需要注意的是,我一开始是考虑第 i 轮要用区间乘实现,后来发现还要还原,有点不可做的感觉

但是再仔细一想,注意到第 i 轮的初始值是整体偏移的,且并不关心单个数值偏移后的具体大小,那我直接求出第一轮的和然后乘上对应的偏移量就可以了

可以拿到 70pts

code
#include <bits/stdc++.h>
#define re register int 
#define lp p << 1
#define rp p << 1 | 1
#define int long longusing namespace std;
typedef long long LL;
const int N = 2e5 + 10;
const LL inf = 1e18;int n, T, a[N];
LL W0, ans;
struct Tree
{int l, r, tag;LL sum;
}t[N << 2];inline void push_up(int p)
{t[p].sum = t[lp].sum + t[rp].sum;	
} inline void push_down(int p)
{if (t[p].tag){t[lp].sum += (LL)(t[lp].r - t[lp].l + 1) * (LL)t[p].tag;t[rp].sum += (LL)(t[rp].r - t[rp].l + 1) * (LL)t[p].tag;t[lp].tag += t[p].tag;t[rp].tag += t[p].tag;t[p].tag = 0;}
}inline void build(int p, int l, int r)
{t[p].l = l, t[p].r = r;if (l == r){t[p].sum = a[l];return;}int mid = (l + r) >> 1;build(lp, l, mid);build(rp, mid + 1, r);push_up(p);
}inline void update(int p, int l, int r, int k)
{if (l <= t[p].l && t[p].r <= r){t[p].sum += (LL)(t[p].r - t[p].l + 1) * k;t[p].tag += k;return;}push_down(p);int mid = (t[p].l + t[p].r) >> 1;if (l <= mid) update(lp, l, r, k);if (r > mid) update(rp, l, r, k);push_up(p);	
}inline LL query(int p, int l, int r)
{if (l <= t[p].l && t[p].r <= r) return t[p].sum;push_down(p);LL res = 0ll;int mid = (t[p].l + t[p].r) >> 1;if (l <= mid) res += query(lp, l, r);if (r > mid) res += query(rp, l, r);return res;
}signed main()
{ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);//	freopen("wxyt3.in", "r", stdin);
//	freopen("wxyt3.out", "w", stdout);cin >> n >> T >> W0;for (re i = 1; i <= n; i ++) cin >> a[i];build(1, 1, n);while (T --){ans = 0ll; LL W = W0;int L, R, d; cin >> L >> R >> d;update(1, L, R, d);LL sum = query(1, 1, n), tot = 0ll, last;int cnt = 0ll; // 实际到第 cnt 轮就死亡 while (tot < W){last = tot;tot = sum * (LL)(1ll << cnt) + last;cnt ++;}ans += (LL)((cnt - 1ll) * n); // 所有点覆盖轮 W -= last;int l = 1, r = n;while (l < r){int mid = (l + r) >> 1;if (W - query(1, 1, mid) * (LL)(1ll << (cnt - 1ll)) <= 0) r = mid;else l = mid + 1;}ans += (LL)(l - 1ll);cout << ans << '\n';}return 0;
}

瓶颈就是它卡两只 log,,,再考虑到线段树本身常数较大(可能树状数组可以冲一下?

可能有其他做法,std 是 \(O(n\log W + q)\) 的,没去看

消去一只 log 的办法就是在线段树上直接二分,找左右子树,很妙的办法

ac code
#include <bits/stdc++.h>
#define re register int
#define lp p << 1
#define rp p << 1 | 1
#define int long longusing namespace std;
typedef long long LL;
const int N = 2e5 + 10;
const LL inf = 1e18;int n, T, a[N];
LL W0, ans;
struct Tree
{int l, r, tag;LL sum;
}t[N << 2];inline void push_up(int p)
{t[p].sum = t[lp].sum + t[rp].sum;
} inline void push_down(int p)
{if (t[p].tag){t[lp].sum += (LL)(t[lp].r - t[lp].l + 1) * (LL)t[p].tag;t[rp].sum += (LL)(t[rp].r - t[rp].l + 1) * (LL)t[p].tag;t[lp].tag += t[p].tag;t[rp].tag += t[p].tag;t[p].tag = 0;}
}inline void build(int p, int l, int r)
{t[p].l = l, t[p].r = r;if (l == r){t[p].sum = a[l];return;}int mid = (l + r) >> 1;build(lp, l, mid);build(rp, mid + 1, r);push_up(p);
}inline void update(int p, int l, int r, int k)
{if (l <= t[p].l && t[p].r <= r){t[p].sum += (LL)(t[p].r - t[p].l + 1) * k;t[p].tag += k;return;}push_down(p);int mid = (t[p].l + t[p].r) >> 1;if (l <= mid) update(lp, l, r, k);if (r > mid) update(rp, l, r, k);push_up(p);	
}inline LL query(int p, int l, int r)
{if (l <= t[p].l && t[p].r <= r) return t[p].sum;push_down(p);LL res = 0ll;int mid = (t[p].l + t[p].r) >> 1;if (l <= mid) res += query(lp, l, r);if (r > mid) res += query(rp, l, r);return res;
}inline int query2(int p, int l, int r, LL W, LL layer)
{if (l == r) return l;push_down(p);int mid = (l + r) >> 1;if (W - t[lp].sum * layer <= 0) return query2(lp, l, mid, W, layer);else return query2(rp, mid + 1, r, W - t[lp].sum * layer, layer); 
}signed main()
{ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);//	freopen("wxyt3.in", "r", stdin);
//	freopen("wxyt3.out", "w", stdout);cin >> n >> T >> W0;for (re i = 1; i <= n; i ++) cin >> a[i];build(1, 1, n);while (T --){ans = 0ll; LL W = W0;int L, R, d; cin >> L >> R >> d;update(1, L, R, d);LL sum = query(1, 1, n), tot = 0ll, last;int cnt = 0ll; // 实际到第 cnt 轮就死亡 while (tot < W){last = tot;tot = sum * (LL)(1ll << cnt) + last;cnt ++;}ans += (LL)((cnt - 1ll) * n); // 所有点覆盖轮 W -= last;int pos = query2(1, 1, n, W, (LL)(1ll << (cnt - 1ll))) - 1;cout << ans + pos << '\n';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/74027.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

低功耗4G模组:tcs3472颜色传感器示例

​ 今天我们学习合宙低功耗4G模组Air780EP的LuatOS开发tcs3472示例,文末【阅读原文】获取最新资料1 一、简介 tcs3472颜色传感器能够读取照射到的物体的RGB三种数值,从而识别颜色关联文档和使用工具:LuatOS 固件获取tcs3472 颜色传感器接口说明Luatools下载调试工具二、材料…

读数据工程之道:设计和构建健壮的数据系统15源系统实际细节(上)

源系统实际细节(上)1. 数据库 1.1. 数据库管理系统1.1.1. 用于存储和提供数据的数据库系统1.1.2. 简称DBMS,它由存储引擎、查询优化器、灾难恢复和其他管理数据库系统的关键组件组成1.1.2.1. 查询1.1.2.2. 查询优化器1.1.2.3. 扩展和分发1.1.2.4. 模型1.1.2.5. CRUD1.1.2.6.…

代码随想录算法训练营第三天 | 203. 移除链表元素、 707. 设计链表、206.反转链表

链表基础 链表分为单链表、双链表和循环链表,链表在内存中与数组不同,不是连续存储的。 C++中链表的定义方式如下: // 单链表 struct ListNode {int val; // 节点上存储的元素ListNode *next; // 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {} // 节点的…

MySQL时区导致无法产生表

MySQL时区导致无法产生表 解决问题加上 &serverTimezone=UTC日志信息 2024-10-21 01:56:19.719 INFO 26556 --- [ main] com.li.BackEndApplication : Starting BackEndApplication on LIJIANTPC with PID 26556 (D:\project\blogs\back-end\tar…

我在大厂做 CR——如何体系化防控空指针异常

大家好,我是木宛哥,今天和大家分享下——代码 CR 时针对恼人的空指针异常(NullPointerException)如何做到体系化去防控; 什么是空指针异常 从内存角度看,对象的实例化需要在堆内存中分配空间。如果一个对象没有被创建,那也就没有分配内存,当应用程序访问空对象时,实际…

U4字符串以及正则表达式

Unit4字符串以及正则表达式方法 描述capitalize() 把首字符转换为大写。casefold() 把字符串转换为小写。center() 返回居中的字符串。count() 返回指定值在字符串中出现的次数。encode() 返回字符串的编码版本。endswith() 如果字符串以指定值结尾,则返回 true。expandtabs()…

内网渗透-内网信息收集

简单内网信息收集分享。目录Windows本地基础信息收集权限查看指定用户的详细信息查看防火墙状态机器基础信息查看系统信息查看进程情况软件安装情况查看计划任务网络环境查看网络配置信息查看网络连接情况查看是否存在域扫描网段WMIC收集信息抓本地密码LaZagne抓密码mimikatz 抓…

jenkins安装提示无法启动

想必大家会遇到以下问题: jenkins安装时因错误导致需要二次或者多次安装jenkins.msi,系统会提示sevice jenkinsfailed to start ,verify that you have sufficient privileges to start system services (服务jenkins启动失败,请确认你有足够的权限来启动系统服务) 解决…