【NOIP2019模拟11.01】Game(贪心+线段树)

匿名 (未验证) 提交于 2019-12-03 00:17:01

Description:

\(1<=n<=10^5\)

考虑求最高的得分。

每个人肯定希望打比他低的又最高的。

所以排个序,扫一遍即可,正着扫倒着扫好像都可以。

现在要字典序最大,考虑逐位确定。

发现每一位可以二分,那么要支持删除的情况下动态维护最高得分。

显然可以线段树,要维护三个标记,已经匹配的,a剩下多少,b剩下多少。

直接搞就是\(O(n~log^2n)\)

考虑线段树多维护一个东西表示在这个区间删掉最左的之后的三个标记。

那就可以在线段树上面二分了,复杂度:\(O(n~log~n)\)

Code:

#include<bits/stdc++.h> #define fo(i, x, y) for(int i = x, B = y; i <= B; i ++) #define ff(i, x, y) for(int i = x, B = y; i <  B; i ++) #define fd(i, x, y) for(int i = x, B = y; i >= B; i --) #define ll long long #define pp printf #define hh pp("\n") using namespace std;  const int N = 1e5 + 5;  int n; int a[N], b[N];  const int inf = 1e9; struct nod {     int x, y, z;     nod() {         x = y = z = 0;     } } t[N * 4], g[N * 4];  #define i0 i + i #define i1 i + i + 1 void upd(nod &a, nod b, nod c) {     if(b.z < 0 || c.z < 0) a.z = -inf; else     a.z = b.z + c.z + min(c.x, b.y);     a.y = c.y + max(0, b.y - c.x);     a.x = b.x + max(0, c.x - b.y); }  int pl, pr, px, py;  void add(int i, int x, int y) {     if(x == y) {         if(!py) t[i].x += px; else t[i].y += px;         g[i] = t[i]; g[i].x --;         if(g[i].x < 0) g[i].z = -inf;         return;     }     int m = x + y >> 1;     if(pl <= m) add(i0, x, m); else add(i1, m + 1, y);     upd(t[i], t[i0], t[i1]);     upd(g[i], g[i0], t[i1]);     if(g[i].z < 0) upd(g[i], t[i0], g[i1]); }  int ans, ans2[N];  nod pc, pd; void qu(int i, int x, int y) {     if(y < pl || x > pr) return;     if(x >= pl && y <= pr) {         upd(pc, pc, t[i]);         return;     }     int m = x + y >> 1;     qu(i0, x, m); qu(i1, m + 1, y); } struct P {     int i, x, y; } d[50]; int d0; void ft(int i, int x, int y) {     if(y < pl || x > pr) return;     int m = x + y >> 1;     if(x >= pl && y <= pr) {         d[++ d0] = (P) {i, x, y};         return;     }     ft(i0, x, m); ft(i1, m + 1, y); } nod p[50], q[50]; void dg(int i, int x, int y) {     int m = x + y >> 1;     nod pe; upd(pe, g[i], pd); upd(pe, pc, pe);     if(pe.z < ans - py) return;     if(x == y) {         px = x; return;     }     pe = pc; upd(pc, pc, t[i0]);     dg(i1, m + 1, y);     pc = pe;     if(px) return;     pe = pd; upd(pd, t[i1], pd);     dg(i0, x, m);     pd = pe; } void gg() {     d0 = 0; ft(1, 1, 1e5);     p[0] = pc; q[d0 + 1] = pd;     fo(i, 1, d0) upd(p[i], p[i - 1], t[d[i].i]);     fd(i, d0, 1) upd(q[i], t[d[i].i], q[i + 1]);     fd(i, d0, 1) {         pc = p[i - 1], pd = q[i + 1];         dg(d[i].i, d[i].x, d[i].y);         if(px) return;     } }  int main() {     freopen("game.in", "r", stdin);     freopen("game.out", "w", stdout);     scanf("%d", &n);     fo(i, 1, 1e5 * 4) g[i].z = -inf, g[i].x = -1;     fo(i, 1, n) scanf("%d", &b[i]);     fo(i, 1, n) scanf("%d", &a[i]);     fo(i, 1, n) {         pl = pr = b[i]; py = 1; px = 1;         add(1, 1, 1e5);         pl = pr = a[i]; py = 0; px = 1;         add(1, 1, 1e5);     }     ans = t[1].z;     fo(i, 1, n) {         pl = pr = b[i]; px = -1; py = 1;         add(1, 1, 1e5);         pl = 1, pr = b[i]; pc = pd = nod();         qu(1, 1, 1e5);         py = 1, pl = b[i] + 1, pr = 1e5; px = 0;         gg();         if(px) {             ans2[i] = px;             ans --;             pl = pr = px; py = 0; px = -1;             add(1, 1, 1e5);             continue;         }         pl = b[i] + 1, pr = 1e5; pc = pd = nod();         qu(1, 1, 1e5); swap(pc, pd);         py = 0, pl = 1, pr = b[i]; px = 0;         gg();         ans2[i] = px;         pl = pr = px; py = 0; px = -1;         add(1, 1, 1e5);     }     fo(i, 1, n) pp("%d ", ans2[i]); hh; } 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!