• bzoj4504 K个串


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4504

    【题解】

    我们初始考虑是能不能O(logn)内求出区间[l,r]内的答案,我们对权值建主席树然后差分(但是不行)。

    所以必须改变思路(!)

    对于每个右端点i,把它所能包含的左端点区间看成主席树来维护的区间。

    再考察修改了啥,就能发现是区间修改,然后单个线段树查询。

    最后套用“超级钢琴”做法即可。

    注意主席树复制标记!!

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, A[M], pre[M];
    struct pa {
        int x, id;
        pa() {}
        pa(int x, int id) : x(x), id(id) {}
        friend bool operator < (pa a, pa b) {
            return a.x < b.x || (a.x == b.x && a.id < b.id);
        }
    }a[M];
    
    struct pb {
        ll w; int ps;
        pb() {}
        pb(ll w, int ps) : w(w), ps(ps) {}
        friend bool operator > (pb a, pb b) {
            return a.w>b.w;
        }
        friend bool operator < (pb a, pb b) {
            return a.w<b.w;
        }
        friend pb operator + (pb a, ll b) {
            return pb(a.w+b, a.ps);
        }
    };
    
    int rt[M];
    namespace CMT {
        const int M = 15000000 + 10;
    
        ll tg[M]; pb w[M];
        int ch[M][2], siz=0;    
        
        inline void build(int &x, int l, int r) {
            x = ++siz; tg[x] = 0; w[x] = pb(0ll, l); 
            if(l == r) return;
            int mid = l+r>>1;
            build(ch[x][0], l, mid); build(ch[x][1], mid+1, r);
        }
        inline void edt(int &x, int y, int l, int r, int L, int R, int ad) {
            if(L>R) return;
            x = ++siz;
            ch[x][0] = ch[y][0]; ch[x][1] = ch[y][1]; tg[x] = tg[y];
            if(L <= l && r <= R) {
                w[x] = w[y] + (ll)ad;
                tg[x] = tg[y] + ad;
                return ;
            }
            int mid = l+r>>1;
            if(R <= mid) edt(ch[x][0], ch[y][0], l, mid, L, R, ad);
            else if(L > mid) edt(ch[x][1], ch[y][1], mid+1, r, L, R, ad);
            else {
                edt(ch[x][0], ch[y][0], l, mid, L, mid, ad);
                edt(ch[x][1], ch[y][1], mid+1, r, mid+1, R, ad);
            }
            if(w[ch[x][0]] > w[ch[x][1]]) w[x] = w[ch[x][0]]; else w[x] = w[ch[x][1]];
            w[x] = w[x] + tg[x];
        }
        
        inline pb ask(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return w[x];
            int mid = l+r>>1;
            if(R <= mid) return ask(ch[x][0], l, mid, L, R) + tg[x];
            else if(L > mid) return ask(ch[x][1], mid+1, r, L, R) + tg[x];
            else {
                pb a, b;
                a = ask(ch[x][0], l, mid, L, mid), b = ask(ch[x][1], mid+1, r, mid+1, R);
                if(b > a) a = b;
                return a + tg[x];
            }
        }    
    }
    
    struct paa {
        int l, r, x, pos; ll va;
        paa() {}
        paa(int l, int r, int x, int pos, ll va) : l(l), r(r), x(x), pos(pos), va(va) {}
        friend bool operator < (paa a, paa b) {
            return a.va < b.va;
        }
    };
    
    priority_queue<paa> q;
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i=1, x; i<=n; ++i) {
            scanf("%d", &x);
            a[i] = pa(x, i);
            A[i] = x;
        }
        sort(a+1, a+n+1);
        for (int i=1, j; i<=n; i=j+1) {
            j = i;
            pre[a[i].id] = 0;
            while(a[j+1].x == a[j].x) {
                pre[a[j+1].id] = a[j].id;
                ++j;
            }
        }
        CMT::build(rt[0], 1, n);
        for (int i=1; i<=n; ++i) CMT::edt(rt[i], rt[i-1], 1, n, pre[i]+1, i, A[i]);
        pb t;
        for (int i=1; i<=n; ++i) {
            t = CMT::ask(rt[i], 1, n, 1, i);
            q.push(paa(1, i, i, t.ps, t.w));
        }
        for (int i=1; i<m; ++i) {
            paa tp = q.top(); q.pop();
    //        printf("%d %d %d %d %lld
    ", tp.l, tp.r, tp.x, tp.pos, tp.va);
            if(tp.l < tp.pos) {
                t = CMT::ask(rt[tp.x], 1, n, tp.l, tp.pos-1);
                q.push(paa(tp.l, tp.pos-1, tp.x, t.ps, t.w));
            }
            if(tp.pos < tp.r) {
                t = CMT::ask(rt[tp.x], 1, n, tp.pos+1, tp.r);
                q.push(paa(tp.pos+1, tp.r, tp.x, t.ps, t.w));
            }
        }
        printf("%lld
    ", q.top().va);
    
        return 0;
    }
    View Code
  • 相关阅读:
    哀悼:设置我们的blog为银灰色
    五子棋算法详解——解决方案之二
    ActionScript3使用角度值控制游戏角色的动作和移动
    LR12中快照的一点使用
    转义字符的一些应用
    关联的一些设置及实践
    检查点函数实践
    LR12的log解释
    struts2的强大迭代标签:<s:iterator>
    正则表达式30分钟入门
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj4504.html
Copyright © 2020-2023  润新知