题目背景
「因为,人类的历史与成长,就是战争的历史与成长。没有纷争,就没有成长。满足于现状,就等于人类放弃了生存。月之民每天都为地上人考虑着。地上人的历史,就是月之民创造的。」
「我对月之民还是很了解的。这么说吧,她们在各式各样的异世界的居民中,属于最恶劣的那一类。超级排他,超级没自由,虚构的乐园,虽然擅长鄙视别人,但无法容忍自己被当成笨蛋。她们甚至认为其他世界的居民连杂菌都不如。」
「最重要的问题是,月之民敌视着幻想乡,就是这样的。」
「没想到竟然会把地上人送到月面上来,之前丝毫没有过这种想法呢。那些眼里容不下一点沙子的月之民,竟然会使用这种不入流的手段。」
「幻想乡被作为人质绑架了,可以这么认为吧?要是想拯救幻想乡的话,就不许对月之都动手,就是这种不人道的策略。」
遥遥 3838 万公里航程之外,于此故乡之星倒映之海,打败不共戴天之敌,击碎永久不得醒之梦。
不倶戴天の敵、嫦娥じょうが嫦娥じょうがよ。見てるか!?
不共戴天之敌,嫦娥啊。你在看着吗!?
题目描述
简要题意
给定一个长度为 �n 的序列,序列中每个元素是一个二元组 (��,��)(ci,ai),分别表示颜色与权值。
现在有 �q 次询问,每次给出一个区间 [�,�][l,r],求:
max�=1�{min�≤�≤�,��=���}k=1maxn{l≤i≤r,ci=kminai}
特别地,如果 [�,�][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,否则 minmin 会变得更小;同理 �R 为颜色为 ��ci 且 ��<��aj<ai,�>�j>i 的 �i 的后继 �j 减 11。若 �L 不存在则为 11,�R 不存在则为 �n。
通过上述分析,可知每个 (��,��)(ai,ci) 对询问的贡献是矩形 [�,�]×[�,�][L,i]×[i,R] 取 maxmax。矩形可以通过对每个颜色按 ��ai 从大到小扫描线 + set 维护求出。
问题转化为矩形取 maxmax,单点查询,且所有查询在加入所有矩形后。对 �x 轴扫描线,在 �=�x=L 处往 �∈[�,�]y∈[i,R] 加入 ��ai,在 �=�+1x=i+1 处从 �∈[�,�]y∈[i,R] 删除 ��ai。非常经典的标记永久化树套树。具体地,加入时往 [�,�][i,R] 的拆分区间维护的平衡树中加入 ��ai,删除同理。查询时查询经过所有节点的平衡树最大值。用 multiset
会被卡常,需要用两个 priority_queue
模拟可删除堆。
时间复杂度 �(�log2�+�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;
}