首页 > 其他分享 >[线段树套单调栈] 2019-2020 ICPC Asia Hong Kong Regional Contest H.[Hold the Line]

[线段树套单调栈] 2019-2020 ICPC Asia Hong Kong Regional Contest H.[Hold the Line]

时间:2022-10-28 10:39:51浏览次数:85  
标签:rt Hong return 树套 dh int res val Hold


线段树套单调栈

2019-2020 ICPC Asia Hong Kong Regional Contest H.​​Hold the Line​

题目大意

你已经建造了一条由编号从到的战壕组成的防线,每条战壕最初都是空的。士兵们正在等待你的命令,每个士兵都有一个喜欢的射击高度。

随着战斗的进行,以下两个事件可能会发生。

  • 一个拥有首选射击高度的士兵被派去驻守一个空的战壕。
  • 一个有高度的敌人被发现,只有驻守在编号在和之间的战壕里的士兵可以射杀这个敌人。为了提高命中率,从而节省子弹,有必要选择一个首选射击高度尽可能接近敌人高度的士兵来射击敌人。你需要知道所选士兵的首选射击高度和敌人的高度之间的差异。

题目思路

非常妙的思路

分别将修改操作和询问操作离线,然后分别按照右端点排序。

然后以高度为下标建立权值线段树,然后将“最接近”转化为两次线段树上二分:求左侧最右和右侧最左,然后取差值最小值即可。

考虑如何检查合法性:由于在权值线段树上丢失了区间信息,因此二分时要检查合法性:我们对每个节点记录两个值:位置和时间戳

那么对于任意两个节点状态,当时间戳,那么第一个节点就可以被后者覆盖。因此对每个节点维护一个随递增且随递减的单调栈。检查合法性时在单调栈上二分查询是否存在的节点即可。

注意此时查询的是最近的操作,而不再是具体的节点。比较抽象,但是很牛逼…

Code

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 1e6 + 10, INF = 1e17;
// int ans[N];

namespace ffastIO {
const int bufl = 1 << 15;
char buf[bufl], *s = buf, *t = buf;
inline int fetch() {
if (s == t) { t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t) return EOF; }
return *s++;
}
inline int read() {
int a = 0, b = 1, c = fetch();
while (!isdigit(c))b ^= c == '-', c = fetch();
while (isdigit(c)) a = a * 10 + c - 48, c = fetch();
return b ? a : -a;
}
}

using ffastIO::read;

#define pii pair<int, int>
#define mkp make_pair
#define fir first
#define sec second

struct chang{ int h, id; };
struct query{ int l, h, id; };

vector<int> dh;
vector<query> que[N];
vector<chang> chg[N];

namespace SegTree{
#define ls rt << 1
#define rs rt << 1 | 1
#define lson ls, l,
#define rson rs, mid + 1,

vector<pii> tree[N << 2];

void build(int rt, int l, int r){
tree[rt].clear();
if(l == r) return;
int mid = l + r >> 1;
build(lson), build(rson);
}

void update(int rt, int l, int r, int h, int pos, int val){
while(tree[rt].size() && tree[rt].back().sec > val) tree[rt].pop_back();
tree[rt].emplace_back(mkp(pos, val));
if(l == r) return;
int mid = l + r >> 1;
if(mid >= h) update(lson, h, pos, val);
else update(rson, h, pos, val);
}

bool check(int rt, int val, int pos){
auto fnd = pii{val, 0};
auto it = lower_bound(tree[rt].begin(), tree[rt].end(), fnd);
if(it != tree[rt].end()) return (*it).second < pos;
else return false;
}

int queryl(int rt, int l ,int r, int L, int R, int val, int pos){
if(l > R || r < L) return INF;
if(l == r) return check(rt, val, pos) ? l : INF * 2;
if(l >= L && r <= R && !check(rt, val, pos)) return INF * 2;
int mid = l + r >> 1, res = INF * 2;
if(res >= INF) res = min(res, queryl(lson, L, R, val, pos));
if(res >= INF) res = min(res, queryl(rson, L, R, val, pos));
return res;
}

int queryr(int rt, int l ,int r, int L, int R, int val, int pos){
if(l > R || r < L) return -1;
if(l == r) return check(rt, val, pos) ? l : -1;
if(l >= L && r <= R && !check(rt, val, pos)) return -1;
int mid = l + r >> 1, res = -1;
if(res < 0) res = max(res, queryr(rson, L, R, val, pos));
if(res < 0) res = max(res, queryr(lson, L, R, val, pos));
return res;
}
}

#define SEGRG 1, 0, siz - 1

inline void solve(){
dh.clear();
int n = read(), m = read();
for(int i = 1; i <= n; i++) chg[i].clear(), que[i].clear();
for(int i = 1; i <= m; i++){
int op = read();
if(op == 0){
int x = read(), h = read();
chg[x].emplace_back(chang{h, i});
dh.emplace_back(h);
} else {
int l = read(), r = read(), h = read();
que[r].emplace_back(query{l, h, i});
dh.emplace_back(h);
}
}
sort(dh.begin(), dh.end());
dh.erase(unique(dh.begin(), dh.end()), dh.end());
auto get = [&](int x){ return lower_bound(dh.begin() , dh.end(), x) - dh.begin(); };
int siz = dh.size();
SegTree::build(SEGRG);
vector<pii> ans;
for(int i = 1; i <= n; i++){
for(auto &[qh, id] : chg[i]){
int h = get(qh);
SegTree::update(SEGRG, h, i, id);
}
for(auto &[l, qh, id] : que[i]){
int h = get(qh);
int lans = SegTree::queryr(SEGRG, 0, h, l, id);
int rans = SegTree::queryl(SEGRG, h + 1, siz - 1, l, id);
int res = INF * 2;
if(lans >= 0) res = min(res, dh[h] - dh[lans]);
if(rans < INF) res = min(res, dh[rans] - dh[h]);
if(res >= INF) res = -1;
ans.emplace_back(mkp(id, res));
}
}
sort(ans.begin(), ans.end());
for(auto &[id, res] : ans) printf("%d\n", res);
}

signed main(){
// ios_base::sync_with_stdio(false), cin.tie(0);
int t = read();
while(t--) solve();
return 0;
}


标签:rt,Hong,return,树套,dh,int,res,val,Hold
From: https://blog.51cto.com/u_12372287/5803535

相关文章

  • 算法分析笔记----wsdchong
    时间:2018/12/20一、算法概述什么是算法1.算法:为一个计算的具体步骤;常用于计算、数据处理、推理等性质:有限、确定、可行、输入、输出;目的:解决问题(问题定义了输入和输出)2.例子......
  • 网站开发的基础知识笔记--wsdchong
    时间:2020/4/21前言:对HTTP的了解、对cookie和session的了解、response和request对象的了解一、对HTTP的了解1概述:HTTP(超文本传输协议Hypertexttransferprotocol)。超文本:不......
  • 前端后端知识体系理解--wsdchong
    时间:2020/4/21前言:对前端的理解、对后端的理解、基于Java的前后端、基于node.js、基于PHP。认识具有反复性和无限性。这是我之前2020/4/13对前后端的理解:前后端学习框架在变......
  • 用SSM框架开发新闻发布管理系统笔记--wsdchong
    前言:在整合三大框架的基础上实现系统后台的用户管理、用户登录、登录验证、新闻发布管理。前台页面使用jQuery+bootstrap框架完成新闻展示;一、系统概述1系统功能需求:用户管......
  • SpringMVC学习笔记--wsdchong
    前言:SpringMVC入门、SpringMVC数据绑定、JSON数据交互和RESTful支持、拦截器、SSM框架整合、一、SpringMVC入门1SpringMVC是spring提供的一个轻量级web框架,实现了webMVC设计......
  • MyBatis学习笔记--wsdchong
    前言:学编程和学绘画一样,都是从模仿开始。初识mybatis、mybatis的核心配置、动态SQL、mybatis的关联映射、与spring的整合。 一、初识mybatis概念:1mybatis是一个支持普通SQL......
  • Spring学习笔记--wsdchong
    前言:理解了基础,就去用轮子,用熟了轮子就再了解基础,然后造轮子。Spring基础、spring的bean、springAOP、spring的数据库开发、spring的事务管理 一、spring基础概念:1spring......
  • 操作系统笔记----wsdchong
    2018/11/14复习内容:理论、七个大题、30个小题;一、操作系统课程内容1.操作系统引论:特性与功能2CPU管理:进程管理(进程同步);处理机调度与死锁(HRN)3存储器管理:存储器管理、虚拟存储......
  • 软件工程笔记----wsdchong
    时间:2018/12/13第1,2章 软件工程、软件过程1.软件危机:“已完成”的软件,不满足用户的需求,进度不能保障,开发成本难测;质量没有保证。2.软件工程的定义是:将系统化的、规范......
  • 数据库的摘要学习----wsdchong
    时间:2020/4/26前言:我们专业是大二下学期学的数据库,那时候学得云里来雾里去,知识点全靠硬记;最近做网站开发,里面涉及到了数据库,就专门拿大二下的书看了一下,结果越看越起劲,越看......