题解:P11787 「FAOI-R4」蒲公英的约定
P11787 「FAOI-R4」蒲公英的约定
我们称『滑档』指一个学生由志愿
发现一条性质:
这条性质联系生活实际不难看出,想必大家都没听说过某个学校减少招生结果本来没被这个学校录取的后来被录取了的这种事情。
或者感性理解一下这个招生的过程,首先
那么看到此题中,我们设
再次回忆这个
我们对每个学校维护什么分数的什么学生被这所学校录取了。每次
新的学生参与排名我们可以用堆简单实现。之后我们还需要支持每个学校快速查询第
我的代码里使用了 __gnu_pbds::tree 实现。可以通过 __gnu_pbds 简单写出一个考场可用的平衡树。其中红黑树 __gnu_pbds::rb_tree_tag 性能最佳。代码里用的就是红黑树。
https://www.luogu.com.cn/record/204321549
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace __gnu_pbds;
using namespace std;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++
char buf[1000000], *p1 = buf, *p2 = buf;
template <typename T>
void read(T &x)
{
x = 0;
int f = 1;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar())
if (c == '-')
f = -f;
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
x *= f;
}
template <typename T, typename... Args>
void read(T &x, Args &...y)
{
read(x);
read(y...);
}
template <class T>
void write(T x)
{
static int stk[30];
if (x < 0)
putchar('-'), x = -x;
int top = 0;
do
{
stk[top++] = x % 10, x /= 10;
} while (x);
while (top)
putchar(stk[--top] + '0');
}
template <class T>
void write(T x, char lastChar) { write(x), putchar(lastChar); }
int n, m, q;
vector<int> a[300020];
int sc[300020];
int p[300020];
int cur[300020];
int t[300020];
int b[300020];
int fa[300020];
int F(int u) { return u ^ fa[u] ? fa[u] = F(fa[u]) : u; }
void U(int u, int v) { fa[F(u)] = F(v); }
int change;
// set<array<int, 2>> s[300020];
tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update> s[300020];
void doit(int f = 0)
{
if (f)
{
map<int, int> done;
set<pair<int, int>> q;
auto add = [&](int f)
{
// cerr << f << ' ' << t[f] << '\n';
// cerr << s[f].size() << '\n';
if (s[f].size() <= t[f])
return;
if (!t[f])
{
while (!s[f].empty())
q.insert(*--s[f].end()), s[f].erase(--s[f].end());
return;
}
int ln = (*s[f].find_by_order(t[f] - 1)).first;
// cerr << "sz,ln: " << s[f].size() << ' ' << ln << '\n';
// cerr << (*--s[f].end()).first << ' ' << (*--s[f].end()).second << '\n';
while (!s[f].empty() && (*--s[f].end()).first > ln)
q.insert(*--s[f].end()), s[f].erase(--s[f].end());
};
change = 0;
add(f);
while (!q.empty())
{
auto [sc, u] = *q.begin();
q.erase(q.begin());
cur[u]++;
if (!done.count(u))
done[u] = 1, change++;
if (cur[u] == a[u].size())
continue;
s[a[u][cur[u]]].insert({sc, u});
add(a[u][cur[u]]);
}
return;
}
change = 0;
map<int, int> mp;
int lst_p = 0;
vector<int> vec;
for (int i = 1; i <= n; i = F(i + 1))
{
int k = p[i];
if (sc[k] != sc[lst_p])
{
for (auto [x, y] : mp)
b[x] += y;
mp.clear();
}
// cerr << k << ' ' << sc[k] << '\n';
int lst = !f ? -1 : cur[k];
for (int &j = cur[k]; j < a[k].size(); j++)
{
if (b[a[k][j]] < t[a[k][j]])
{
mp[a[k][j]]++;
break;
}
else
{
}
}
// cerr << cur[k] << '\n';
if (cur[k] == a[k].size())
vec.emplace_back(i);
change += cur[k] != lst;
lst_p = k;
}
for (auto [x, y] : mp)
b[x] += y;
mp.clear();
// cerr << "vec " << vec.size() << '\n';
// for (int i : vec)
// cerr << i << ' ';
// cerr << '\n';
for (int i : vec)
U(i, i + 1);
for (int i = 1; i <= n; i++)
{
if (cur[i] < a[i].size())
s[a[i][cur[i]]].insert({-sc[i], i});
}
}
int main()
{
read(n, m, q);
for (int i = 1; i <= m; i++)
read(t[i]);
for (int i = 1; i <= n; i++)
{
int len;
read(len);
a[i].resize(len);
for (int &j : a[i])
read(j);
read(sc[i]);
}
for (int i = 1; i <= n; i++)
p[i] = i;
for (int i = 1; i <= n; i++)
fa[i] = i;
fa[n + 1] = n + 1;
sort(p + 1, p + n + 1, [&](int x, int y)
{ return sc[x] > sc[y]; });
doit(0);
// cout << change << '\n';
// for (int i = 1; i <= n; i++)
// cout << (cur[i] == a[i].size() ? 0 : a[i][cur[i]]) << ' ';
// cout << '\n';
while (q--)
{
int x, v;
read(x, v);
// cerr << "sub: " << x << ' ' << v << '\n';
t[x] -= v;
// cerr << t[x] << '\n';
doit(x);
write(change, '\n');
// for (int i = 1; i <= n; i++)
// cout << (cur[i] == a[i].size() ? 0 : a[i][cur[i]]) << ' ';
// cout << '\n';
}
return 0;
}