给一些互不包含的区间和一些石子堆,按顺序依次从区间内取走一些石子且每次有上限,要求每次都尽量取最多石子。
假设前面的 i−1 个区间全部满足了,且第 j 个区间取到了 kj ,现在要在第 i 个区间取石子。设当前区间会取 x 个石子,我们将每个区间拆成 ki 个点,划作 X 集,往石子堆可取的区间内的所有点连边。若第 k 堆石子有 ak 颗,则也拆成 ak 个点,划为 Y 集。若要使能取的条件全部成立,则意味着表示 X 端的点全部和 Y 端的点匹配。我们用Hall定理来处理,对于区间 i 以外的区间节点是已经满足了的,可以不用管;对于包含区间 i 的区间集合:若这些区间并起来不连续,那么显然可以拆成两个独立的连续区间而互不影响;若有两个区间的并包含第三个区间,则算上第三个区间的约束会比不算第三个区间的约束更紧。由此,因为区间均不包含,将当前所加入的区间全部排序后,我们只需要处理包含 i 的“区间的区间”的约束即可。设 p 为区间 i 的排名, si=∑rik=1ak,ti=∑li−1k=1ak , ki 为排名前 i 的区间所取到的石子的和,则约束可以表示成 sr−tl≥kr−kl−1+x,l≤p≤r ,可以得到 x 的上限是 min{sr−kr}−max{tl−kl−1} 。不断插入区间然后线段树维护最值即可。
时间复杂度 O(mlogm) ,但是不知道为什么在bzoj上跑的这么慢,明明只有4w的数据范围。。。
哦数据里好像有 m<2 的要特判一下。
#include
using namespace std;
#define rep(i,a,b) for (int i = a, _ = b; i <= _; i ++)
const int inf = 0x3fffffff;
const int maxn = 40007;
const int maxs = (1 << 17) + 7;
typedef int seg[maxs];
typedef int arr[maxn];
#define T int u, int l, int r
#define L lc , l , m
#define R rc , m + 1 , r
#define lc (u << 1)
#define rc (u << 1 | 1)
seg mn, mx, s1, s2, tg1, tg2;
arr a, l, r, k, h;
int v1, v2, v, ql, qr;
int n, m;
bool cmp(const int i, const int j) {
return l[i] < l[j];
}
void upd(int u) {
mn[u] = min(mn[lc], mn[rc]);
mx[u] = max(mx[lc], mx[rc]);
}
void B(T) {
mn[u] = inf, mx[u] = -inf;
if (l == r) return;
int m = (l + r) >> 1;
B(L), B(R);
}
void tag1(int u, int v) {
mn[u] -= v, s1[u] += v, tg1[u] += v;
}
void tag2(int u, int v) {
mx[u] -= v, s2[u] += v, tg2[u] += v;
}
void push(int u) {
if (tg1[u]) {
tag1(lc, tg1[u]), tag1(rc, tg1[u]);
tg1[u] = 0;
}
if (tg2[u]) {
tag2(lc, tg2[u]), tag2(rc, tg2[u]);
tg2[u] = 0;
}
}
int get(T, int p) {
if (l == r) return s1[u];
int m = (l + r) >> 1; push(u);
return p <= m ? get(L, p) : get(R, p);
}
void que(T) {
if (ql <= l && r <= qr) {
v1 = min(v1, mn[u]);
v2 = max(v2, mx[u]);
return;
}
push(u);
int m = (l + r) >> 1;
if (ql <= m) que(L);
if (qr > m) que(R);
}
void gao(T, int p) {
if (l == r) {
mn[u] = a[::r[h[l]]] - s1[u];
mx[u] = a[::l[h[l]] - 1] - s2[u];
return;
}
int m = (l + r) >> 1;
push(u);
if (p <= m) gao(L, p); else gao(R, p);
upd(u);
}
void gao1(T) {
if (ql <= l && r <= qr) {
tag1(u, v);
return;
}
int m = (l + r) >> 1; push(u);
if (ql <= m) gao1(L);
if (qr > m) gao1(R);
upd(u);
}
void gao2(T) {
if (ql <= l && r <= qr) {
tag2(u, v);
return;
}
int m = (l + r) >> 1; push(u);
if (ql <= m) gao2(L);
if (qr > m) gao2(R);
upd(u);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int x, y, z, P;
scanf("%d", &n);
scanf("%d%d%d%d", &x, &y, &z, &P);
rep (i , 1 , n) a[i] = ((i - x) * (i - x) % P + (i - y) * (i - y) % P + (i - z) * (i - z) % P) % P, a[i] += a[i - 1];
//rep (i , 1 , n) cerr << a[i] << " "; cerr << endl;
scanf("%d", &m);
scanf("%d%d%d%d%d%d", &k[1], &k[2], &x, &y, &z, &P);
rep (i , 3 , m) k[i] = (x * k[i - 1] % P + y * k[i - 2] % P + z) % P;
rep (i , 1 , m) scanf("%d%d", &l[i], &r[i]);
if (m < 2) {
rep (i , 1 , m) printf("%d\n", min(a[r[i]] - a[l[i] - 1], k[i]));
return 0;
}
rep (i , 1 , m) h[i] = i;
B(1, 1, m);
static arr rk;
sort(h + 1, h + m + 1, cmp);
rep (i , 1 , m) rk[h[i]] = i;
rep (i , 1 , m) {
int l = ::l[i], r = ::r[i], k = ::k[i], p = rk[i];
int x = get(1, 1, m, p);
v1 = a[r] - x;
ql = p + 1, qr = m;
if (ql <= qr)
que(1, 1, m);
int tmp = v1;
v2 = a[l - 1] - x;
ql = 1, qr = p - 1;
if (ql <= qr)
que(1, 1, m);
v1 = tmp;
v = min(k, min(v1 - v2, a[r] - a[l - 1]));
printf("%d\n", v);
ql = p, qr = m;
gao1(1, 1, m);
ql = p + 1 , qr = m;
if (ql <= qr)
gao2(1, 1, m);
gao(1, 1, m, p);
}
return 0;
}