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\n", 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\n", q.top().va); return 0; }