voiddivide (int l, int r) {
if (l == r) return f[l] = max (f[l], 1), void ();
int mid = l + r >>1;
divide (l, mid);
for (int i = l; i <= r; i ++) tmp[i] = p[i];
sort (p + l, p + mid +1);
sort (p + mid +1, p + r +1);
for (int i = mid +1, j = l; i <= r; i ++) {
while (j <= mid && p[j].mx <= p[i].a) { t.ist (p[j].a, f[p[j].i]); j ++; }
f[ p[i].i ] = max (f[ p[i].i ], t.qry (p[i].mn) +1);
}
for (int i = l; i <= mid; i ++) t.del (p[i].a);
for (int i = l; i <= r; i ++) p[i] = tmp[i];
divide (mid +1, r);
}
#include<vector>#include<iostream>#define mid (l + r >> 1)
usingnamespace std;
constint N =1e6+10;
constint P =1e9+7;
constint inf =1e9;
inlineintadd (int u, int v) {
u += v;
if (u >= P) u -= P;
if (u <0) u += P;
return u;
}
structdata {
int f, g;
data (int f =-inf, int g =0) : f(f), g(g) {}
};
inline data get (data x, data y) {
if (x.f == y.f) return data (x.f, add (x.g, y.g));
return x.f > y.f ?x : y;
}
int n;
int c[N], d[N], L[N], R[N];
data f[N];
vector <int> scanl[N];
structSegmenTree {
data t[N <<2];
#define ls (u << 1)
#define rs (u << 1 | 1)
voidpushup (int u) { t[u] = get (t[ls], t[rs]); }
voidmodify (int u, int l, int r, int qq, data k) {
if (qq > r || qq < l) return;
if (l == r) return t[u] = k, void ();
if (qq <= mid) modify (ls, l, mid, qq, k);
else modify (rs, mid +1, r, qq, k);
pushup (u);
}
data query (int u, int l, int r, int ql, int qr) {
if (ql > qr) return data ();
if (l >= ql && r <= qr) return t[u];
data ret = data ();
if (mid >= ql) ret = get (ret, query (ls, l, mid, ql, qr));
if (qr > mid) ret = get (ret, query (rs, mid +1, r, ql, qr));
return ret;
}
} sgt;
voiddivide (int l, int r) {
if (l == r) return ;
divide (l, mid); for (int i = mid +1; i <= r +1; i ++) scanl[i].clear ();
int mxl =1, mnr = n;
for (int i = mid; i >= l; i --) {
L[i] = mxl + i, R[i] = mnr + i;
if (mxl > mnr || R[i] <= mid) break ;
if (L[i] <= r)
scanl[max (mid +1, L[i])].push_back (i),
scanl[min (r +1, R[i] +1)].push_back (i + N);
mxl = max (mxl, c[i]), mnr = min (mnr, d[i]);
}
mxl =1, mnr = n;
for (int j = mid +1; j <= r; j ++) {
for (constauto&p : scanl[j]) {
if (p < N) sgt.modify (1, 0, n, p, f[p]);
else sgt.modify (1, 0, n, p - N, data ());
}
mxl = max (c[j], mxl), mnr = min (d[j], mnr);
if (mnr < mxl || j - mnr > mid) break;
auto res = sgt.query (1, 0, n, max (l, j - mnr), min (mid, j - mxl)); res.f ++;
f[j] = get (f[j], res);
}
for (int i = l; i <= mid; i ++) sgt.modify (1, 0, n, i, data ());
divide (mid +1, r);
}
intmain (void) {
scanf ("%d", &n);
for (int i =1; i <= n; i ++) scanf ("%d%d", c + i, d + i);
f[0] = data (0, 1);
divide (0, n);
if (f[n].f <0) puts ("NIE");
else printf ("%d %d\n", f[n].f, f[n].g);
return0;
}
$Q$ 天降陨石,每次形如 l r v,指区间 $[l,r]$(若 $l>r$,则是 $[l,n]\cup[1,r]$)降下 $v$ 个陨石。
对于每个国家,求最少天,使期望达到。
$n,m,Q\le 3\times 10^5$。
你看,和上面所说的做法是不是一模一样?
维护区间的差分数组,单点修改区间查询。就做完了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
voiddivide (int l, int r, int ql, int qr) {
int mid = ql + qr >>1;
int c1 =0, c2 =0;
if (ql == qr) {
for (int i = l; i <= r; i ++) ans[ctry[i]] = ql;
return ;
}
while (now < mid) modify (++ now, 1); while (now > mid) modify (now --, -1);
for (int i = l; i <= r; i ++) {
ll res =0; int nowc = ctry[i];
for (autov : cotry[nowc]) res += t.qry (v);
if (res >= p[nowc]) wctry[++ c1] = nowc;
else wwctry[++ c2] = nowc;
}
for (int i =1; i <= c1; i ++) ctry[l + i -1] = wctry[i];
for (int i =1; i <= c2; i ++) ctry[l + c1 + i -1] = wwctry[i];
if (c1) divide (l, l + c1 -1, ql, mid);
if (c2) divide (l + c1, l + c1 + c2 -1, mid +1, qr);
}