不要手贱写树套树!!!
本题草场可以看成是线段, 我用线段树维护这些线段, 每个节点存一个 set
维护覆盖这个节点的线段.
每次查询全局最大值, 然后把覆盖这个单点的所有线段在树上抹去.
我这样的算法会在某些情况出问题, 如果有三条线段表示开区间:
(1,2), (1,7), (4,10), (9,10).
如果我一开始选择了线段 (1,7), (4,10), 之后需要再选两次才能选完这些线段. 总共需要选 3 次.
但是这 4 条线段只需要两次就可以全部选完, 所以这个做法是错误的.
pair<unsigned, unsigned> Grass[200005];
unsigned Rg[200005][2], Cow[200005], b[400005];
unsigned Stack[200005], STop(0);
unsigned long long Ans(0);
unsigned m, n, My;
unsigned A, B, C, D, t;
unsigned Cnt(0), Tmp(0);
struct Node {
set<unsigned> List;
Node* LS, *RS;
unsigned long long Mx, Tag;
unsigned MxP;
}N[800005], *CntN(N);
inline void Build(Node*x, unsigned L, unsigned R) {
x->MxP = L;
if(L == R) return;
unsigned Mid((L + R) >> 1);
Build(x->LS = ++CntN, L, Mid);
Build(x->RS = ++CntN, Mid + 1, R);
}
inline void Chg(Node* x, unsigned L, unsigned R) {
// printf("Chg %u [%u, %u] for [%u, %u]\n", x - N, L, R, A, B);
if((A <= L) && (R <= B)) {
x->List.insert(C), x->Tag += Grass[C].second, x->Mx += Grass[C].second;
return;
}
unsigned Mid((L + R) >> 1);
if(A <= Mid) Chg(x->LS, L, Mid);
if(B > Mid) Chg(x->RS, Mid + 1, R);
if(x->LS->Mx >= x->RS->Mx) x->Mx = x->Tag + x->LS->Mx, x->MxP = x->LS->MxP;
else x->Mx = x->Tag + x->RS->Mx, x->MxP = x->RS->MxP;
}
inline void Access(Node* x, unsigned L, unsigned R) {
// printf("Access %u (%u) [%u, %u] LS %u RS %u\n", x - N, A, L, R, x->LS - N, x->RS - N);
for (auto i:x->List) Stack[++STop] = i;
if(L == R) return;
unsigned Mid((L + R) >> 1);
if(A <= Mid) Access(x->LS, L, Mid);
else Access(x->RS, Mid + 1, R);
}
inline void Ers(Node* x, unsigned L, unsigned R) {
// printf("Ers %u [%u, %u] for [%u, %u]\n", x - N, L, R, A, B);
if((A <= L) && (R <= B)) {
// printf("Erase %u\n", C);
x->List.erase(C);
// for (auto i:x->List) printf("%u ", i); putchar(0x0A);
x->Tag -= Grass[C].second, x->Mx -= Grass[C].second;
return;
}
unsigned Mid((L + R) >> 1);
if(A <= Mid) Ers(x->LS, L, Mid);
if(B > Mid) Ers(x->RS, Mid + 1, R);
if(x->LS->Mx >= x->RS->Mx) x->Mx = x->Tag + x->LS->Mx, x->MxP = x->LS->MxP;
else x->Mx = x->Tag + x->RS->Mx, x->MxP = x->RS->MxP;
}
// inline void Clr() {}
signed main() {
freopen("9.in", "r", stdin);
// freopen(".out", "w", stdout);
// t = RD();
// for (unsigned T(1); T <= t; ++T){
// Clr();
n = RD(), m = RD(), My = RD();
for (unsigned i(1); i <= n; ++i) Grass[i].first = RD() + 1, Grass[i].second = RD();
for (unsigned i(1); i <= m; ++i) Cow[i] = RD() + 1;
sort(Grass + 1, Grass + n + 1), sort(Cow + 1, Cow + m + 1);
Cow[0] = 0, Cow[++m] = 1000000002;
for (unsigned i(0), j(1); j <= n; ++j) {
while(Cow[i + 1] < Grass[j].first) ++i;
unsigned Dis;
if((i ^ (m - 1)) && ((!i) || (Cow[i + 1] - Grass[j].first < Grass[j].first - Cow[i]))) {
Rg[j][1] = Cow[i + 1];
Dis = Cow[i + 1] - Grass[j].first;
Rg[j][0] = (Dis <= Grass[j].first) ? (Grass[j].first - Dis + 1) : 1;
}
else {
Rg[j][0] = Cow[i] + 1;
Dis = Grass[j].first - Cow[i];
Rg[j][1] = Grass[j].first + Dis;
}
}
for (unsigned i(1); i <= n; ++i) b[++Cnt] = Rg[i][0], b[++Cnt] = Rg[i][1];
sort(b + 1, b + Cnt + 1), Cnt = unique(b + 1, b + Cnt + 1) - b;
printf("Cnt %u\n", Cnt);
Build(N, 1, Cnt - 1);
for (unsigned i(1); i <= n; ++i) {
A = Rg[i][0] = lower_bound(b + 1, b + Cnt, Rg[i][0]) - b;
B = Rg[i][1] = lower_bound(b + 1, b + Cnt, Rg[i][1]) - b;
C = i, Chg(N, 1, Cnt - 1);
}
// for (auto i:Test) printf("%u ", i); putchar(0x0A);
while (My && N->Mx) {
Ans += N->Mx, ++D;
A = N->MxP, Access(N, 1, Cnt - 1);
// sort(Stack + 1, Stack + STop + 1), STop = unique(Stack + 1, Stack + STop + 1) - Stack - 1;
// printf("This Time %llu (%u) Size %u\n", N->Mx, N->MxP, STop);
// for (unsigned i(1); i <= STop; ++i) printf("%u ", Stack[i]); putchar(0x0A);
// system("pause");
for (unsigned i(1); i <= STop; ++i)
C = Stack[i], A = Rg[C][0], B = Rg[C][1], Ers(N, 1, Cnt - 1);
--My, STop = 0;
}
printf("%llu %u\n", Ans, D);
return Wild_Donkey;
}