【BZOJ 2138】stone

来源:互联网 发布:淘宝潘多拉哪家是正品 编辑:程序博客网 时间:2024/06/03 23:46

  给一些互不包含的区间和一些石子堆,按顺序依次从区间内取走一些石子且每次有上限,要求每次都尽量取最多石子。


  假设前面的i1个区间全部满足了,且第j个区间取到了kj,现在要在第i个区间取石子。设当前区间会取x个石子,我们将每个区间拆成ki个点,划作X集,往石子堆可取的区间内的所有点连边。若第k堆石子有ak颗,则也拆成ak个点,划为Y集。若要使能取的条件全部成立,则意味着表示X端的点全部和Y端的点匹配。我们用Hall定理来处理,对于区间i以外的区间节点是已经满足了的,可以不用管;对于包含区间i的区间集合:若这些区间并起来不连续,那么显然可以拆成两个独立的连续区间而互不影响;若有两个区间的并包含第三个区间,则算上第三个区间的约束会比不算第三个区间的约束更紧。由此,因为区间均不包含,将当前所加入的区间全部排序后,我们只需要处理包含i的“区间的区间”的约束即可。设p为区间i的排名,si=rik=1ak,ti=li1k=1akki为排名前i的区间所取到的石子的和,则约束可以表示成srtlkrkl1+x,lpr,可以得到x的上限是min{srkr}max{tlkl1}。不断插入区间然后线段树维护最值即可。
  时间复杂度O(mlogm),但是不知道为什么在bzoj上跑的这么慢,明明只有4w的数据范围。。。
  哦数据里好像有m<2的要特判一下。


#include <bits/stdc++.h>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;}
原创粉丝点击