Solution -「JOISC 2021」「LOJ #3489」饮食区
Link.
呐……不想概括题意,自己去读叭~
如果仅有 1. 3. 操作,能不能做?
——简单整体二分。
如果仅有 1. 2. 操作,能不能实时维护每个位置还剩下多少人?累计走了多少人?
——吉司机线段树。
所以,离线下来,把上两个重工业揉在一起就能粗暴地过掉这道题√ 复杂度 ( 同阶)。
有 而且短得多的算法欸,问 Tiw 嘛 qwq。
/* Clearink */
#include <cstdio>
#include <vector>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef long long LL;
#define int LL
template<typename Tp = int>
inline Tp rint() {
Tp x = 0; int s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() );
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
inline LL lmin( const LL a, const LL b ) { return a < b ? a : b; }
const int MAXN = 2.5e5;
const LL LINF = 1ll << 60;
int n, m, q;
std::vector<int> allq;
struct Event {
int a, b, c; LL d;
inline void read() {
if ( int op = rint(); op == 1 ) {
a = rint(), b = rint(), c = rint(), d = rint();
} else if ( op == 2 ) {
a = -1, b = rint(), c = rint(), d = rint();
} else {
a = b = -2, c = rint(), d = rint<LL>();
}
}
} evt[MAXN + 5];
struct SegmentTree {
LL tag[MAXN << 2];
inline void clear( const int u, const int l, const int r ) {
tag[u] = 0;
if ( l == r ) return ;
int mid = l + r >> 1;
clear( u << 1, l, mid ), clear( u << 1 | 1, mid + 1, r );
}
inline void modify( const int u, const int l, const int r,
const int ml, const int mr, const LL v ) {
if ( ml <= l && r <= mr ) return void( tag[u] += v );
int mid = l + r >> 1;
if ( ml <= mid ) modify( u << 1, l, mid, ml, mr, v );
if ( mid < mr ) modify( u << 1 | 1, mid + 1, r, ml, mr, v );
}
inline LL query( const int u, const int l, const int r, const int x ) {
if ( l == r ) return tag[u];
int mid = l + r >> 1;
if ( x <= mid ) return tag[u] + query( u << 1, l, mid, x );
else return tag[u] + query( u << 1 | 1, mid + 1, r, x );
}
} sgt; // It's for both Init and Solve.
namespace Init {
struct JiSegmentTree {
LL tag1[MAXN << 2], tag2[MAXN << 2], mnv[MAXN << 2], smn[MAXN << 2];
inline void clear( const int u, const int l, const int r ) {
smn[u] = LINF;
if ( l == r ) return ;
int mid = l + r >> 1;
clear( u << 1, l, mid ), clear( u << 1 | 1, mid + 1, r );
}
inline void pushad( const int u, const LL v1, const LL v2 ) {
tag1[u] += v1, mnv[u] += v1;
if ( smn[u] != LINF ) smn[u] += v2, tag2[u] += v2;
}
inline void pushdn( const int u ) {
int a = mnv[u << 1], b = mnv[u << 1 | 1];
if ( a <= b ) pushad( u << 1, tag1[u], tag2[u] );
else pushad( u << 1, tag2[u], tag2[u] );
if ( b <= a ) pushad( u << 1 | 1, tag1[u], tag2[u] );
else pushad( u << 1 | 1, tag2[u], tag2[u] );
tag1[u] = tag2[u] = 0;
}
inline void pushup( const int u ) {
mnv[u] = lmin( mnv[u << 1], mnv[u << 1 | 1] );
smn[u] = LINF;
if ( mnv[u] < mnv[u << 1] ) smn[u] = lmin( smn[u], mnv[u << 1] );
if ( mnv[u] < mnv[u << 1 | 1] )
smn[u] = lmin( smn[u], mnv[u << 1 | 1] );
if ( mnv[u] < smn[u << 1] ) smn[u] = lmin( smn[u], smn[u << 1] );
if ( mnv[u] < smn[u << 1 | 1] )
smn[u] = lmin( smn[u], smn[u << 1 | 1] );
}
inline void modify( const int u, const int l, const int r,
const int ml, const int mr, const LL v ) {
if ( ml <= l && r <= mr ) return pushad( u, v, v );
int mid = l + r >> 1; pushdn( u );
if ( ml <= mid ) modify( u << 1, l, mid, ml, mr, v );
if ( mid < mr ) modify( u << 1 | 1, mid + 1, r, ml, mr, v );
pushup( u );
}
inline void upto( const int u, const int l, const int r,
const int ul, const int ur, const LL v ) {
if ( mnv[u] >= v ) return ;
if ( ul <= l && r <= ur && v < smn[u] )
return pushad( u, v - mnv[u], 0 );
int mid = l + r >> 1; pushdn( u );
if ( ul <= mid ) upto( u << 1, l, mid, ul, ur, v );
if ( mid < ur ) upto( u << 1 | 1, mid + 1, r, ul, ur, v );
pushup( u );
}
inline LL query( const int u, const int l, const int r, const int x ) {
if ( l == r ) return mnv[u];
int mid = l + r >> 1; pushdn( u );
if ( x <= mid ) return query( u << 1, l, mid, x );
else return query( u << 1 | 1, mid + 1, r, x );
}
} jsgt;
inline void init() {
jsgt.clear( 1, 1, n );
rep ( i, 1, q ) {
if ( evt[i].a >= 0 ) {
sgt.modify( 1, 1, n, evt[i].a, evt[i].b, evt[i].d );
jsgt.modify( 1, 1, n, evt[i].a, evt[i].b, evt[i].d );
} else if ( evt[i].a == -1 ) {
jsgt.modify( 1, 1, n, evt[i].b, evt[i].c, -evt[i].d );
jsgt.upto( 1, 1, n, evt[i].b, evt[i].c, 0 );
} else {
allq.push_back( i );
evt[i].d += sgt.query( 1, 1, n, evt[i].c )
- jsgt.query( 1, 1, n, evt[i].c );
}
}
}
} // namespace Init.
namespace Solve {
int ans[MAXN + 5];
inline void divide( const int l, const int r, const std::vector<int>& qvec ) {
if ( qvec.empty() ) return ;
if ( l == r ) {
for ( int q: qvec ) ans[q] = l;
return ;
}
int mid = l + r >> 1;
rep ( i, l, mid ) if ( evt[i].a >= 0 ) {
sgt.modify( 1, 1, n, evt[i].a, evt[i].b, evt[i].d );
}
std::vector<int> qlef, qrig;
for ( int q: qvec ) {
if ( sgt.query( 1, 1, n, evt[q].c ) >= evt[q].d ) qlef.push_back( q );
else qrig.push_back( q );
}
divide( mid + 1, r, qrig );
rep ( i, l, mid ) if ( evt[i].a >= 0 ) {
sgt.modify( 1, 1, n, evt[i].a, evt[i].b, -evt[i].d );
}
divide( l, mid, qlef );
}
inline void solve() {
sgt.clear( 1, 1, n );
divide( 1, q + 1, allq );
rep ( i, 1, q ) if ( evt[i].a == -2 ) {
wint( ans[i] > i ? 0 : evt[ans[i]].c ), putchar( '\n' );
}
}
} // namespace Solve.
signed main() {
n = rint(), m = rint(), q = rint();
rep ( i, 1, q ) evt[i].read();
Init::init();
Solve::solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现