zoukankan      html  css  js  c++  java
  • Taotao Picks Apples

    ps:这题的难点,寻找修改的位置之后有多少个苹果能被吃掉,比赛的时候想到的是讨论修改的位置,预处理每个位置的最大值和吃到苹果的数量,记最大值所在的位置为 id, 记修改的位置为 pos,分三种情况讨论,① pos < id,维护一个从 id ~ 1的递减序列,修改后在这个序列里二分查找。② pos == id,维护一个 id + 1 ~ n的递增序列,修改后二分查找。三 pos > id,随便做。是不是感觉我说得很有道理~~~~,然而我并没写出来。实际上,这题离线后就好做了,从后往前维护一个单调栈,当前的元素修改了,就在单调栈中二分查找,O(mlog(n))。讲真,原来询问问题只有两种:强制在线和没要求……为啥我现在菜知道,orz。离线后一般要对询问排序,要不然离线没意义。(所以莫队的思想是很有用的),400ms哟

    // 膜强无敌的老师: https://paste.ubuntu.com/p/jFChknqmCD/
    inline void upd(int &x, int y) { x < y && (x = y); } const int N = 100005; int n, m; int a[N], cnt[N], Max[N], ans[N]; vector<int> v; vector<P> q[N]; void Inite() { v.clear(); cnt[0] = Max[0] = 0; for (int i = 1; i <= n; ++i) { cnt[i] = cnt[i - 1]; Max[i] = Max[i - 1]; if (a[i] > Max[i - 1]) cnt[i]++, Max[i] = a[i]; } } int main() { //freopen("D:\1.in", "r", stdin); //freopen("D:\1.txt", "w", stdout); BEGIN() { sc(n), sc(m); for (int i = 1; i <= n; ++i) sc(a[i]), q[i].clear(); Inite(); for (int i = 1; i <= m; ++i) { int pos, x; sc(pos), sc(x); q[pos].pb(P(x, i)); } for (int i = n; i >= 1; --i) { for (auto &p : q[i]) { int pos, x; tie(x, pos) = p; int res = cnt[i - 1] + (x > Max[i - 1]); upd(x, Max[i - 1]); res += v.rend() - upper_bound(v.rbegin(), v.rend(), x); ans[pos] = res; } while(v.size() && v.back() <= a[i]) v.pp(); v.pb(a[i]); } for (int i = 1; i <= m; ++i) pr(ans[i]); } return 0; }

     补充:线段树也可以做的,主席树也可以。因为对于每个点我们需要向后找最近的大于它的一个值。假设修改的位置为pos ,树的每个区间存的是该区间的最大值,那么我们就可以去寻找(pos + 1, n)这个区间比 a[pos] 大的位置在哪。具体看代码~,言而总之,总而言之,我们的目的是预处理出 从 i 这个位置向后递增的序列长度。因为实现不太优秀的原因,跑了700多ms

    inline void upd(int &x, int y) { x < y && (x = y); }
    
    /* 比较扯的是 N = 100005 会RE,OMG,就真的不能一发过吗? */
    const int N = 200005; int n, m, tot, mPos; int a[4 * N], b[N], cnt[N], Max[N], d[N]; map<int, int> id; void Inite() { mem(d, 0); cnt[0] = Max[0] = 0; for (int i = 1; i <= n; ++i) { cnt[i] = cnt[i - 1]; Max[i] = Max[i - 1]; if (b[i] > Max[i - 1]) cnt[i]++, Max[i] = b[i]; } } inline void Pushup(int root) { a[root] = max(a[lson], a[rson]); } void Build(int l, int r, int root) { if (l == r) { sc(a[root]); id[root] = ++tot; b[tot] = a[root]; return; } int mid = (l + r) >> 1; Build(l, mid, lson); Build(mid + 1, r, rson); Pushup(root); }

    /*
    写挂了的查询!① mPos可能存在,但if过后直接退出而查不到那个位置去,② 当找到mPos后可能在其它节点再次被更新,而且会T,因为查询的代价可能不再是O(log(n))
    void Query(int l, int r, int root, int L, int R, int x) {
       if
    (l > R || r < L || L > R) return;
        if
    (L <= l && r <= R && l == r) {
            mPos = id[root];
            return
    ;
        }

        int
    mid = (l + r) >> 1;
        if
    (a[lson] > x) Query(l, mid, lson, L, R, x);
        else if
    (a[rson] > x) Query(mid + 1, r, rson, L, R, x);
    }

    */
    void Query(int l, int r, int root, int L, int R, int x) { if (l > R || r < L || L > R || mPos != -1) return; if (L <= l && r <= R && l == r) { mPos = id[root]; return; } int mid = (l + r) >> 1; if (a[lson] > x) Query(l, mid, lson, L, R, x); if (a[rson] > x) Query(mid + 1, r, rson, L, R, x); } int main() { //freopen("D:\1.in", "r", stdin); //freopen("D:\1.txt", "w", stdout); BEGIN() { sc(n), sc(m); tot = 0; Build(1, n, 1); Inite(); for (int i = n; i; --i) { mPos = -1; Query(1, n, 1, i + 1, n, b[i]); if (mPos == -1) d[i] = 1; else d[i] = d[mPos] + 1; } //for (int i = 1; i <= n; ++i) cout << i << " " << d[i] << endl; for (int i = 1; i <= m; ++i) { int pos, x; sc(pos), sc(x); int res = cnt[pos - 1] + (x > Max[pos - 1]); upd(x, Max[pos - 1]); mPos = -1; Query(1, n, 1, pos + 1, n, x); if (mPos != -1) res += d[mPos]; pr(res); } } return 0; }

     又ps:有心情的话我会补充主席树的代码,以及dp和倍增的代码,比较难求的东西只有一个,实现的方式只是手段。

  • 相关阅读:
    一个简单的加载动画,js实现
    banner无缝滚动动画,支持左右按钮和小点
    自动检测ie低版本,并显示升级浏览器的自定义页面,当用f12再把浏览器版本提高的时候,又会自动显示正常的页面。
    banner轮播无缝滚动 jq代码
    css 实现背景图片不跟着滚动条滚动而滚动
    截取字符串指定内容,并用*号代替
    日历获取当前月份的月数与当前月份第一天离第一个格子的位置。
    MUI 自定义从底部弹出的弹出框
    textarea 字体限制,超出部分不显示并及时显示还剩字体个数
    清除ul li里面的浮动并让ul自适应高度的一个好办法
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9486649.html
Copyright © 2011-2022 走看看