题解[CEOI2020]权力药水
Posted SharpnessV
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[CEOI2020]权力药水相关的知识,希望对你有一定的参考价值。
题意不是很复杂,只不过出题人强行把题面写的很长。
首先 \\(D\\) 很小,所以对于每个询问,我们可以直接找出两个人信任的人的集合,然后双指针扫一遍即可。
对询问离线,然后维护每个人的集合即可,这道题就做完了(
但是本题强制在线,把小清新模拟题强行变成毒瘤题。
我们需要记录,每个人,在每一时刻,信任的人的集合,这复杂度是 \\(\\mathcal{O}(NMD)\\) 的,显然不行。
考虑对每个人动态开点,那么剩下的状态数是 \\(\\mathcal{O}(MD)\\) 还是吃不消。
\\(M\\) 比较大,将时间作为动态开点的下标,那么对于一个关系 \\((x,y)\\),可以计算出它在图中存活的时间段,然后在线段树中区间加。
因为是动态开点线段树,所以我们需要标记永久化。最后在线段树上单点查询即可得到集合,排序后跑双指针得到答案。
时间复杂度 \\(\\mathcal{O}(M\\log M+QD\\log D)\\)。另外本题卡空间,观察一下发现不少关系 \\((x,y)\\) 的存活时间都是从某个时间开始,一直持续到结束。对于这类关系,我们直接对每个点开一个变长数组维护即可。因为这类关系对每个点的贡献也不会超过 \\(D\\)。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 100005
#define ef 1000000000
using namespace std;
struct node {
int l, r;
vector<int>u;
} a[N * 55];
#define ls a[x].l
#define rs a[x].r
#define S a[x].u
int n, D, m, q, u[N], rt[N], idx;
void ins(int &x, int l, int r, int L, int R, int val) {
if (!x)
x = ++idx;
if (L >= l && R <= r) {
a[x].u.push_back(val);
return ;
}
int mid = (L + R) >> 1;
if (mid >= l)
ins(ls, l, r, L, mid, val);
if (mid < r)
ins(rs, l, r, mid + 1, R, val);
}
vector<int>c[2];
void ask(int x, int L, int R, int pos, int op) {
if (!x)
return;
for (int i = 0; i < (int)a[x].u.size(); i++)
c[op].push_back(a[x].u[i]);
if (L == R)
return;
int mid = (L + R) >> 1;
if (mid >= pos)
ask(ls, L, mid, pos, op);
else
ask(rs, mid + 1, R, pos, op);
}
vector<pair<int, int>>ad[N];
map<pair<int, int>, int>h;
inline void calc() {
int p = c[0].size(), q = c[1].size();
if (!p || !q) {
cout << ef << endl;
return;
}
sort(c[0].begin(), c[0].end());
sort(c[1].begin(), c[1].end());
int j = 0, mn = 0x7fffffff;
rep(i, 0, q - 1) {
while (j < p - 1 && c[0][j] <= c[1][i])
j++;
mn = min(mn, abs(c[0][j] - c[1][i]));
if (j)
mn = min(mn, abs(c[0][j - 1] - c[1][i]));
}
cout << mn << endl;
}
int main() {
scanf("%d%d%d%d", &n, &D, &m, &q);
rep(i, 1, n)scanf("%d", &u[i]);
rep(i, 1, m) {
int x, y;
scanf("%d%d", &x, &y);
x++, y++;
if (x > y)
swap(x, y);
pair<int, int> cur = make_pair(x, y);
if (h.count(cur)) {
ins(rt[x], h[cur], i - 1, 1, m, u[y]);
ins(rt[y], h[cur], i - 1, 1, m, u[x]);
h.erase(h.find(cur));
} else
h.insert(make_pair(cur, i));
}
for (map<pair<int, int>, int>::iterator it = h.begin(); it != h.end(); it++) {
int x = (*it).first.first, y = (*it).first.second;
ad[x].push_back(make_pair(u[y], (*it).second));
ad[y].push_back(make_pair(u[x], (*it).second));
}
while (q--) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
x++, y++;
c[0].clear();
c[1].clear();
if (z) {
ask(rt[x], 1, m, z, 0), ask(rt[y], 1, m, z, 1);
for (int i = 0; i < (int)ad[x].size(); i++)
if (ad[x][i].second <= z)
c[0].push_back(ad[x][i].first);
for (int i = 0; i < (int)ad[y].size(); i++)
if (ad[y][i].second <= z)
c[1].push_back(ad[y][i].first);
calc();
} else
cout << ef << endl;
}
return 0;
}
以上是关于题解[CEOI2020]权力药水的主要内容,如果未能解决你的问题,请参考以下文章