P8543 「Wdoi-2」纯粹的复仇女神

这是一道关于算法的题目,涉及序列处理和区间查询。给定一个包含颜色和权值的序列,以及一系列区间询问,目标是找出每个区间内颜色相同的灵符最小污秽值的最大值,以此计算灵梦净化一次的灵力花费。题目通过矩形区域的处理和平衡树的数据结构来解决,具有较高的复杂度挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目背景

「因为,人类的历史与成长,就是战争的历史与成长。没有纷争,就没有成长。满足于现状,就等于人类放弃了生存。月之民每天都为地上人考虑着。地上人的历史,就是月之民创造的。」

「我对月之民还是很了解的。这么说吧,她们在各式各样的异世界的居民中,属于最恶劣的那一类。超级排他,超级没自由,虚构的乐园,虽然擅长鄙视别人,但无法容忍自己被当成笨蛋。她们甚至认为其他世界的居民连杂菌都不如。」

「最重要的问题是,月之民敌视着幻想乡,就是这样的。」

「没想到竟然会把地上人送到月面上来,之前丝毫没有过这种想法呢。那些眼里容不下一点沙子的月之民,竟然会使用这种不入流的手段。」

「幻想乡被作为人质绑架了,可以这么认为吧?要是想拯救幻想乡的话,就不许对月之都动手,就是这种不人道的策略。」

遥遥 3838 万公里航程之外,于此故乡之星倒映之海,打败不共戴天之敌,击碎永久不得醒之梦。

不倶戴天の敵、嫦娥じょうが嫦娥じょうがよ。見てるか!?
不共戴天之敌,嫦娥啊。你在看着吗!?

题目描述

简要题意

给定一个长度为 �n 的序列,序列中每个元素是一个二元组 (��,��)(ci​,ai​),分别表示颜色与权值。

现在有 �q 次询问,每次给出一个区间 [�,�][l,r],求:

max⁡�=1�{min⁡�≤�≤�,��=���}k=1maxn​{l≤i≤r,ci​=kmin​ai​}

特别地,如果 [�,�][l,r] 内没有颜色为 �k 的值,后面的部分定义为 00。

原始题意

纯狐的能力是纯化,一旦灵梦身上的污秽被纯化,则必死无疑。

灵梦携带了 �n 张一字排开的灵符用于转嫁污秽,但纯狐依旧可以纯化附着在上面的污秽,置灵梦于死地。

具体地,每次纯狐命中一个区间 [��,��][li​,ri​] 中的所有灵符,灵梦需要在此之前净化这些灵符上面的污秽。
每张灵符有固定的颜色 ��ci​,经过激烈的战斗,每张灵符上沾染了 ��ai​ 单位的污秽。
同种颜色的灵符之间相互作用,净化区间内一批相同颜色的灵符,其灵力花费为这些灵符上污秽的最小值。
由于逸散的灵力可以为其他灵符所吸收,灵梦只需知道该区间内所有颜色的灵符净化花费的最大值,此为她净化一次的灵力花费。

给定 {��}{ci​} 和 {��}{ai​},每次给出纯狐的一种可能的攻击 ��,��li​,ri​,问灵梦净化一次的灵力花费。注意只是计算,每次给出答案后并不改变 {��}{ci​} 和 {��}{ai​}。

输入格式

第一行两个整数 �,�n,q,表示序列长度与询问次数。

第二行 �n 个整数,依次为 �1,�2,⋯ ,��c1​,c2​,⋯,cn​。

第三行 �n 个整数,依次为 �1,�2,⋯ ,��a1​,a2​,⋯,an​。

接下来 �q 行,每行两个整数 �,�l,r,表示每次询问给出的区间。

输出格式

共 �q 行,每行一个整数,表示本次询问的答案。

输入输出样例

输入 #1复制

10 10
3 2 2 1 2 1 3 2 1 2 
10 4 10 4 9 8 1 4 9 4 
3 4
3 9
4 8
3 6
3 3
9 10
5 8
5 8
6 8
5 8

输出 #1复制

10
4
4
9
10
9
8
8
8
8

对于每个 (��,��)(ai​,ci​),考虑 ��ai​ 作为区间所有 ��=��cj​=ci​ 的 ��aj​ 的最小值时,合法左右端点的形态。可知若询问左端点落在 [�,�][L,i],右端点落在 [�,�][i,R],则本次询问答案至少不小于 ��ai​,其中 �L 为颜色为 ��ci​ 且 ��<��aj​<ai​,�<�j<i 的 �i 的前驱 �j 加 11:左端点不能跨过 �j,否则 min⁡min 会变得更小;同理 �R 为颜色为 ��ci​ 且 ��<��aj​<ai​,�>�j>i 的 �i 的后继 �j 减 11。若 �L 不存在则为 11,�R 不存在则为 �n。

通过上述分析,可知每个 (��,��)(ai​,ci​) 对询问的贡献是矩形 [�,�]×[�,�][L,i]×[i,R] 取 max⁡max。矩形可以通过对每个颜色按 ��ai​ 从大到小扫描线 + set 维护求出。

问题转化为矩形取 max⁡max,单点查询,且所有查询在加入所有矩形后。对 �x 轴扫描线,在 �=�x=L 处往 �∈[�,�]y∈[i,R] 加入 ��ai​,在 �=�+1x=i+1 处从 �∈[�,�]y∈[i,R] 删除 ��ai​。非常经典的标记永久化树套树。具体地,加入时往 [�,�][i,R] 的拆分区间维护的平衡树中加入 ��ai​,删除同理。查询时查询经过所有节点的平衡树最大值。用 multiset 会被卡常,需要用两个 priority_queue 模拟可删除堆。

时间复杂度 �(�log⁡2�+�log⁡�)O(nlog2n+qlogn)。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ull = unsigned long long;
inline ll read() {
  ll x = 0, sgn = 0;
  char s = getchar();
  while(!isdigit(s)) sgn |= s == '-', s = getchar();
  while(isdigit(s)) x = x * 10 + s - '0', s = getchar();
  return sgn ? -x : x;
}
inline void print(int x) {
  if(x < 0) return putchar('-'), print(-x);
  if(x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}
bool Mbe;
constexpr int N = 2e5 + 5;
constexpr int Q = 1e6 + 5;
void cmin(int &x, int y) {x = x < y ? x : y;}
void cmax(int &x, int y) {x = x > y ? x : y;}
pii d[N];
int n, q, cnt, c[N], a[N], ans[Q];
set<int> s[N];
priority_queue<int> val[N << 2], era[N << 2];
vector<pair<pii, int>> add[N];
vector<pii> qu[N];
void modify(int l, int r, int ql, int qr, int x, int v) {
  if(ql <= l && r <= qr) {
    if(v > 0) val[x].push(v);
    else era[x].push(-v);
    return;
  }
  int m = l + r >> 1;
  if(ql <= m) modify(l, m, ql, qr, x << 1, v);
  if(m < qr) modify(m + 1, r, ql, qr, x << 1 | 1, v);
}
int query(int l, int r, int p, int x) {
  int ans = 0;
  while(!era[x].empty() && val[x].top() == era[x].top()) val[x].pop(), era[x].pop();
  if(!val[x].empty()) ans = val[x].top();
  if(l == r) return ans;
  int m = l + r >> 1;
  return max(ans, p <= m ? query(l, m, p, x << 1) : query(m + 1, r, p, x << 1 | 1));
}
bool Med;
signed main() {
  fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
  #ifdef ALEX_WEI
    FILE* IN = freopen("1.in", "r", stdin);
    FILE* OUT = freopen("1.out", "w", stdout);
  #endif
  cin >> n >> q;
  for(int i = 1; i <= n; i++) c[i] = read(), s[c[i]].insert(i);
  for(int i = 1; i <= n; i++) a[i] = read(), d[i] = {a[i], i};
  sort(d + 1, d + n + 1);
  for(int i = n, pt = n; i; i--) {
    while(pt && d[pt].first == i) {
      int id = d[pt--].second, col = c[id];
      auto pt = s[col].find(id);
      int l = 1, r = n;
      if(pt != s[col].begin()) l = *--pt + 1, pt++;
      if(pt != --s[col].end()) r = *++pt - 1, pt--;
      s[col].erase(pt);
      add[l].push_back({{id, r}, i});
      add[id + 1].push_back({{id, r}, -i});
    }
  }
  for(int i = 1; i <= q; i++) {
    int l = read(), r = read();
    qu[l].push_back({r, i});
  }
  for(int i = 1; i <= n; i++) {
    for(auto it : add[i]) modify(1, n, it.fi.fi, it.fi.se, 1, it.se);
    for(auto it : qu[i]) ans[it.se] = query(1, n, it.fi, 1);
  }
  for(int i = 1; i <= q; i++) print(ans[i]), putchar('\n');
  cerr << TIME << " ms\n";
  return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值