题解 P4849 【寻找宝藏】

huyufeifei

2018-11-22 13:47:04

Solution

这是比赛题,附上[链接](https://www.luogu.org/contestnew/show/9354),里面有官方题解。 ------------ CDQ套CDQ裸题... 不会CDQ分治的请去陌上花开。 然后关于CDQ套CDQ,我觉得[stdcall的博客](https://www.cnblogs.com/mlystdcall/p/6232324.html)写的不错。 大概就是,在第一层CDQ分治的时候,对于左边和右边进行标记,然后不进行任何操作,按照第二维排序后进入第二层CDQ分治。 在第二层里面也对左右进行标记,然后按照第三维排序,树状数组更新DP值即可。 这里要说一个CDQ分治刚学时极易写错的点:**排序一定要彻底!** 按照第二维排序的时候,如果二,三,四维都相同,那么要按照第一维排序。同理,按照第三维排序的时候,如果三,四维都相同,就要再按照一,二维来排序。 不这样做就会以奇怪的姿势挂掉... 比如我有两个四元组: ```text 2 2 2 3 1 2 2 3 ``` 显然第二个是可以更新第一个的,但是如果你在按照第三维排序的时候不小心把第二个放在后面(c++ sort是不稳定的),就凉了。 然后要记得随时取模,就没啥问题了。 CDQ分治嵌套其实可以只用一个函数完成,参考标程的实现。 ~~为什么我写的比标程慢2倍啊......~~ 上代码: ```cpp #include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N = 80010; const LL MO = 998244353; struct Node { int a, b, c, d, id; bool A, B;   LL val, cnt, f; inline bool operator <(const Node &w) const { if(a != w.a) { return a < w.a; } if(b != w.b) { return b < w.b; } if(c != w.c) { return c < w.c; } return d < w.d;  } inline bool operator ==(const Node &w) const { return a == w.a && b == w.b && c == w.c && d == w.d; } }node[N], t1[N], t2[N]; int n, X[N];   namespace ta { LL cnt[N], f[N]; inline void add(int x, LL v, LL sum) { for(; x <= n; x += x & (-x)) { if(v > f[x]) { f[x] = v; cnt[x] = sum; } else if(v == f[x]) { cnt[x] += sum; cnt[x] %= MO; } } return; }  inline void ask(int x, LL &ff, LL &sum, LL val) { for(; x > 0; x -= x & (-x)) { if(f[x] + val > ff) { ff = f[x] + val; sum = cnt[x]; } else if(f[x] + val == ff) { sum += cnt[x]; sum %= MO; } } return; } inline void del(int x) {  for(; x <= n; x += x & (-x)) { cnt[x] = f[x] = 0; } return; } } inline bool cmp_c(const Node &x, const Node &y) { if(x.c != y.c) { return x.c < y.c; } if(x.d != y.d) {  return x.d < y.d; } if(x.a != y.a) { return x.a < y.a; } return x.b < y.b; } inline bool cmp_b(const Node &x, const Node &y) { if(x.b != y.b) { return x.b < y.b; } if(x.c != y.c) { return x.c < y.c; }  if(x.d != y.d) { return x.d < y.d; } return x.a < y.a; } void CDQ_2(int l, int r) { if(l == r) { return; } int mid = (l + r) >> 1; CDQ_2(l, mid); for(int i = l; i <= r; i++) { t1[i].B = (i > mid); t2[i] = t1[i]; t2[i].id = i; }  std::sort(t2 + l, t2 + r + 1, cmp_c); for(int i = l; i <= r; i++) { if(t2[i].A && t2[i].B) { ta::ask(t2[i].d, t2[i].f, t2[i].cnt, t2[i].val); t1[t2[i].id].f = t2[i].f; t1[t2[i].id].cnt = t2[i].cnt; } if(!t2[i].A && !t2[i].B) { ta::add(t2[i].d, t2[i].f, t2[i].cnt); } }  for(int i = l; i <= mid; i++) { if(!t1[i].A) { ta::del(t1[i].d); } } CDQ_2(mid + 1, r); return; } void CDQ_1(int l, int r) { if(l == r) { return; }   int mid = (l + r) >> 1; CDQ_1(l, mid); for(int i = l; i <= r; i++) { node[i].A = (i > mid); t1[i] = node[i]; t1[i].id = i; } std::sort(t1 + l, t1 + r + 1, cmp_b); CDQ_2(l, r); for(int i = l; i <= r; i++) { node[t1[i].id].f = t1[i].f;  node[t1[i].id].cnt = t1[i].cnt; } CDQ_1(mid + 1, r); return; } int main() { int m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d%d%d%d%lld", &node[i].a, &node[i].b, &node[i].c, &node[i].d, &node[i].val); } std::sort(node + 1, node + n + 1);  int temp = 1; for(int i = 2; i <= n; i++) { /// unique if(node[i] == node[temp]) { node[temp].val += node[i].val; } else { node[++temp] = node[i]; } } n = temp; for(int i = 1; i <= n; i++) { X[i] = node[i].a; } std::sort(X + 1, X + n + 1); temp = std::unique(X + 1, X + n + 1) - X - 1; for(int i = 1; i <= n; i++) {  node[i].a = std::lower_bound(X + 1, X + temp + 1, node[i].a) - X; } for(int i = 1; i <= n; i++) { X[i] = node[i].b; } std::sort(X + 1, X + n + 1); temp = std::unique(X + 1, X + n + 1) - X - 1; for(int i = 1; i <= n; i++) { node[i].b = std::lower_bound(X + 1, X + temp + 1, node[i].b) - X; } for(int i = 1; i <= n; i++) { X[i] = node[i].c; }  std::sort(X + 1, X + n + 1); temp = std::unique(X + 1, X + n + 1) - X - 1; for(int i = 1; i <= n; i++) { node[i].c = std::lower_bound(X + 1, X + temp + 1, node[i].c) - X; } for(int i = 1; i <= n; i++) { X[i] = node[i].d; } std::sort(X + 1, X + n + 1); temp = std::unique(X + 1, X + n + 1) - X - 1; for(int i = 1; i <= n; i++) {  node[i].d = std::lower_bound(X + 1, X + temp + 1, node[i].d) - X; } for(int i = 1; i <= n; i++) { node[i].f = node[i].val; node[i].cnt = 1; node[i].id = i; } // prework OVER CDQ_1(1, n);  LL sum = 0, ans = 0; for(int i = 1; i <= n; i++) { if(node[i].f > ans) { ans = node[i].f; sum = node[i].cnt; } else if(node[i].f == ans) { sum += node[i].cnt; sum %= MO; } } printf("%lld\n%lld\n", ans, sum);  return 0; } ```