题目

https://codeforces.com/gym/103260/problem/H

思路


写了一坨答辩代码,已经神志不清了,后面再补上思路吧,先给上题解的描述还有草稿纸上一些图。
简而言之,学会了一种套路,求一些线段中选出不被任何一个线段完全覆盖的所有线段,支持删除线段操作。

代码

#include <bits/stdc++.h>
using namespace std;#define MAXN 500005int n, q;
int a[MAXN];
pair<pair<int, int>, int> Q[MAXN];#define LX (x<<1)
#define RX ((x<<1)|1)struct segment_tree {struct node {int l, r;int v;      // 区间最大值int num;    // 区间线段个数int tag;    // 区间加标记} a[MAXN*8];void merge(int x) {if (a[x].l == a[x].r) return;a[x].num = a[LX].num + a[RX].num;a[x].v = max(a[LX].v, a[RX].v);}void build(int x, int l, int r) {a[x].l = l;a[x].r = r;a[x].num = a[x].tag = 0;a[x].v = -1;if (l == r) return;build(LX, l, (l+r)/2);build(RX, (l+r)/2+1, r);merge(x);}void down_tag(int x) {if (a[x].l == a[x].r) return;if (a[LX].num) a[LX].v += a[x].tag, a[LX].tag += a[x].tag;if (a[RX].num) a[RX].v += a[x].tag, a[RX].tag += a[x].tag;a[x].tag = 0;}void set(int x, int pos, int v) {       // 将线段 pos 处的值设置为 v,若 v==-1 则说明清除这个点if (a[x].l == a[x].r) {a[x].v = v;a[x].num = (v>=0);return;}down_tag(x);if (a[LX].r >= pos) set(LX, pos, v);else set(RX, pos, v);merge(x);}void add(int x, int L, int R, int d) {  // 给区间内存在的线段 +dif (!a[x].num) return;if (L<=a[x].l && a[x].r<=R) {a[x].tag += d;a[x].v += d;return;}down_tag(x);if (a[LX].r>=L) add(LX, L, R, d);if (a[RX].l<=R) add(RX, L, R, d);merge(x);}int query(int x, int pos) {         // 查询 pos 处的值if (a[x].l == a[x].r) {return a[x].v;}down_tag(x);if (a[LX].r >= pos) return query(LX, pos);return query(RX, pos);}int mxv(int x) {                    // 查询整个线段的最大值,若线段为空则返回-1return a[x].num ? a[x].v : -1;}int id_mxv(int x) {                 // 返回最大值所在的下标(左端点)(有多个则随便一个)if (a[x].l == a[x].r) {return a[x].l;}down_tag(x);return (a[LX].v == a[x].v) ? id_mxv(LX) : id_mxv(RX);}} A;struct segment_tree1 {struct node {int l, r;pair<int, int> v;   // <maxr, qid>} a[MAXN*8];void build(int x, int l, int r) {a[x].l = l;a[x].r = r;if (l == r) return;build(LX, l, (l+r)/2);build(RX, (l+r)/2+1, r);}void set(int x, int pos, pair<int, int> v) {if (a[x].l == a[x].r) {a[x].v = v;return;}if (a[LX].r >= pos) set(LX, pos, v);else set(RX, pos, v);a[x].v = (a[RX].v.first > a[LX].v.first) ? a[RX].v : a[LX].v;   // maxr 相同,取左边的}pair<int, int> query(int x, int L, int R) {if (L<=a[x].l && a[x].r<=R) {return a[x].v;}pair<int, int> lv, rv;if (a[LX].r >= L) lv = query(LX, L, R);if (a[RX].l <= R) rv = query(RX, L, R);return (rv.first>lv.first) ? rv : lv;}} B;struct BIT {int c[MAXN];int lowbit(int x) {return x&(-x);}void add(int x, int v) {for (; x<=n; x+=lowbit(x)) c[x]+=v;}int query(int x) {int ret=0;for (; x>0; x-=lowbit(x)) ret+=c[x];return ret;}int query(int l, int r) {return query(r)-query(l-1);}
} C;vector<int> pos_val[MAXN];          // pos_val[v] = {i | a[i]==v}
vector<int> qid_l[MAXN];
int active_qid_l[MAXN];
int ans[MAXN];
set<pair<int, int>> active_l;       // <l, qid>
set<pair<int, int>> active_r;       // <r, qid>void add_qseg(int ql) {int qid = qid_l[ql].back();int qr = Q[qid].first.second;active_l.insert({ql, qid});active_r.insert({qr, qid});active_qid_l[ql] = qid;int tmp = C.query(ql, qr);A.set(1, ql, tmp);qid_l[ql].pop_back();if (qid_l[ql].size()) {B.set(1, ql, {Q[qid_l[ql].back()].first.second, qid_l[ql].back()});}else {B.set(1, ql, {0, 0});}
}void del_qseg(int ql) {int qid = active_qid_l[ql];int qr = Q[qid].first.second;active_l.erase({ql, qid});active_r.erase({qr, qid});A.set(1, ql, -1);
}void activate_qseg(int tmpl, int tmpr, int minr) {while (tmpr>=tmpl) {auto [_, qid] = B.query(1, tmpl, tmpr);if (!qid || Q[qid].first.second < minr) break;add_qseg(Q[qid].first.first);tmpr = Q[qid].first.first-1;}
}void solve()
{scanf("%d%d", &n, &q);for (int i=1; i<=n; i++) {scanf("%d", &a[i]);pos_val[a[i]].push_back(i);}for (int i=1; i<=q; i++) {Q[i].second = i;scanf("%d%d", &Q[i].first.first, &Q[i].first.second);}A.build(1, 1, n);B.build(1, 1, n);for (int i=1; i<=n; i++) C.add(i, 1);sort(Q+1, Q+q+1);for (int i=1; i<=q; i++) qid_l[Q[i].first.first].push_back(i);for (int i=1; i<=q; i++) if (Q[i].first.first != Q[i-1].first.first) {int ql = Q[i].first.first;int qid = qid_l[ql].back();int qr = Q[qid].first.second;B.set(1, ql, {qr, qid});}activate_qseg(1, n, 0);for (int x=n; x>=0; x--) {for (int pos: pos_val[x]) {auto p_l = active_r.lower_bound({pos, 0});auto p_r = active_l.upper_bound({pos, n});int L=n+1, R=0;if (p_l != active_r.end()) {L = Q[p_l->second].first.first;}if (p_r != active_l.begin()) {p_r--;R = p_r->first;}if (L <= R) {A.add(1, L, R, -1);}C.add(pos, -1);}while (A.mxv(1) >= x) {int cur_l = A.id_mxv(1);int cur_id = active_qid_l[cur_l];int cur_r = Q[cur_id].first.second;ans[Q[cur_id].second] = x;int tmpl = cur_l, tmpr = cur_r, minr = 0;auto p_nxt = ++active_l.find({cur_l, cur_id});if (p_nxt != active_l.end()) {tmpr = min(tmpr, Q[p_nxt->second].first.first - 1);}auto p_lst = active_r.find({cur_r, cur_id});if (p_lst != active_r.begin()) {p_lst--;minr = Q[p_lst->second].first.second + 1;}del_qseg(cur_l);activate_qseg(tmpl, tmpr, minr);}}for (int i=1; i<=q; i++) {printf("%d\n", ans[i]);}}int main()
{solve();
}

H. Excluded Min (思维、线段树)相关推荐

  1. P2787 语文1(chin1)- 理理思维(线段树)

    P2787 语文1(chin1)- 理理思维(线段树) 对每个字母开一棵线段树 操作1就是区间查询 操作2就是区间修改 操作3可以看成 先预处理查询出区间对应的每个字母的个数,然后进行区间修改. 然后 ...

  2. duliu——思维+线段树

    题目 [题目描述] 小 `D` 喜欢出毒瘤题毒人.当然,他的毒瘤更多体现在若干个难题组合在同一场比赛时. 小 `D` 脑中有 $n$ 个毒瘤题 idea,第 $i$ 个的毒值为$d_i$.当第 $i$ ...

  3. 牛客-小H的询问(线段树)

    原题链接:更好的阅读体验 题目描述 小H给你一个数组{a},要求支持以下两种操作: 0 l r(1<=l<=r<=n),询问区间[l,r]中权值和最大的有效子区间的权值和,一个子区间 ...

  4. CodeForces ABBYY Cup 3.0 - Finals B Shave Beaver! (思维+线段树)

    题目链接 题意:给你n个数1~n的序列,随后又q次询问,每次询问有2种操作,操作1:查询从序列中取出数值为x,x+1,...,y-1,y的数的最少需要取多少次(且每取一次只能是一个递增的子序列)    ...

  5. AtCoder - arc120_c Swaps 2(思维+线段树+模拟)

    题目链接:点击查看 题目大意:给出一个序列 aaa,问能否经过有限此操作使其变成 bbb,每次操作分为三步: 选择一个 iii,满足 i+1<=ni+1<=ni+1<=n,然后 sw ...

  6. Interesting Array CodeForces - 483D(思维+线段树)

    We'll call an array of n non-negative integers a[1], a[2], -, a[n] interesting, if it meets m constr ...

  7. HDU 4417 Super Mario(线段树离线处理/主席树)

    Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...

  8. Codeforces 1108 E2(线段树+思维)

    传送们 题意: 给你一个长度为nnn的数列bbb.以及mmm个区间. 你可以选取111个或多个这样的区间aia_iai​,使得令区间aia_iai​所对应的所有值bib_ibi​都减111.你最终要使 ...

  9. 小翔和泰拉瑞亚(线段树+思维)

    链接:https://ac.nowcoder.com/acm/contest/3566/D 来源:牛客网 小翔和泰拉瑞亚 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K ...

最新文章

  1. Neumorphism.io一个神奇的网站,满足各种圆角矩形ICON图表立体化效果要求,这种样式的名称——新拟态
  2. 线段树(点查询、区间查询、区间修改)模板
  3. 【通知】深度学习之人脸图像算法核心代码开源和勘误汇总
  4. Java开发专业通过swot分析岗位_掌起智能科技 | 你们要的安卓岗位来了,还有JAVA,技术经理等岗位...
  5. 60分钟快速入门PyTorch
  6. Tapioca:linux上同gtalk语音通信
  7. Visual Studio 2017 警告C4819解决方案
  8. SecureCRT配置详细图文教程
  9. 近日总结3.17-3.19(windows server)
  10. 怎么把图片文字转换成文字
  11. LTE上行物理层传输机制(1)-PUSCH上行跳频之Type1频率跳频
  12. 字节跳动工程师收入世界第五,2021年全球程序员收入报告出炉
  13. uni-app截屏截取页面可视区,以及利用截屏截取完整页面方法
  14. 如何更好的做线上引流
  15. 历史上康熙皇帝真的很喜欢微服私访吗?
  16. alicode git push rejected 的解决
  17. 如何将win10电脑主题设置成深色
  18. python右键idel消失问题
  19. 小白兔是世界上笑话最多的禽兽
  20. OSA-3空气温湿度传感器

热门文章

  1. argparse库的使用
  2. 数字IC设计的前端设计和后端设计流程
  3. 人工智能专业学什么?
  4. Spring Framework --wenyu2
  5. 安卓手机的电话功应用需改进的地方-通话页易误拨
  6. 全国计算机数字图形图像应用技术等级二级,全国计算机数字图形图像应用技术等级考试(广东省)专家交流会...
  7. Flutter Tips之 - Presenting Futures in Flutter
  8. 编程新手入门:初学编程的正确学习方法!快速提升你的学习效率
  9. 凡人重果,菩薩重因。
  10. Linux xxd命令详解