选举 [数据结构优化dp]

选举


Description\mathcal{Description}

在这里插入图片描述


Solution\mathcal{Solution}

F[i]i,F[i]=max{F[j]+1         (sumi>sumj)F[j]                (sumi=sumj)F[j]1         (sumi<sumj)设F[i]表示前i个选民的最优答案,得到\\ F[i]=max\begin{cases} F[j]+1\ \ \ \ \ \ \ \ \ (sum_i>sum_j) \\ F[j] \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (sum_i=sum_j)\\ F[j]-1\ \ \ \ \ \ \ \ \ (sum_i<sum_j) \end{cases}
复杂度 O(N2)O(N^2).

:优化部分:
sumn{sum_n} 为下标建立 权值线段树,
线段树的每个叶子节点保存 sumi=\color{blue}{满足sum_i=叶子下标} 的每个 ii 位置上的 F[]\color{red}{最大F[]值}.

则可以直接查询比当前 sumisum_i小的,大的,相等的 最大的 F[j]F[j], O(logn)O(logn) 实现单次转移.

每次 i++i++ , iL+1i-L+1 可以被合法转移, iR+1i-R+1 不能被合法转移, 于是在线段树中删除掉其对应的 dpdp 值.


bug
Code\mathcal{Code}

#include<bits/stdc++.h>
#define reg register
typedef std::pair<int, int> pr;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 1e6 + 6;
const int inf = 0x3f3f3f3f;

int N;
int L;
int R;
int Lim;
int A[maxn];
int F[maxn];
int sum[maxn];

struct Node{
        std::priority_queue <pr> que;
        int l, r, max_v;
} T[maxn*4];

void Build(int k, int l, int r){ //
        T[k].l = l, T[k].r = r;
        if(l == r){ T[k].max_v = -inf; return ; }
        int mid = l+r >> 1;
        Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
        T[k].max_v = -inf; 
}

void Modify(int k, int id){ //
        int l = T[k].l, r = T[k].r;
        if(l == r){ 
                T[k].que.push(pr(F[id], id)); 
                T[k].max_v = T[k].que.top().first;
                return ;
        }
        int mid = l+r >> 1;
        if(sum[id] <= mid) Modify(k<<1, id);
        else Modify(k<<1|1, id);
        T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v);
}

void Del(int k, int id){ //
        int l = T[k].l, r = T[k].r;
        if(l == r){
                while(!T[k].que.empty() && T[k].que.top().second < Lim) T[k].que.pop();
                if(T[k].que.empty()) T[k].max_v = -inf;
                else T[k].max_v = T[k].que.top().first;
                return ;
        }
        int mid = l+r >> 1;
        if(sum[id] <= mid) Del(k<<1, id);
        else Del(k<<1|1, id);
        T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v);
}

int Query(int k, int Ql, int Qr){ //
        int l = T[k].l, r = T[k].r;
        if(Ql <= l && r <= Qr) return T[k].max_v;
        int mid = l+r >> 1;
        if(mid+1 <= Ql) return Query(k<<1|1, Ql, Qr);
        else if(mid >= Qr) return Query(k<<1, Ql, Qr); 
        return std::max(Query(k<<1, Ql, Qr), Query(k<<1|1, Ql, Qr));
}

int main(){
        freopen("election.in", "r", stdin);
        freopen("election.out", "w", stdout);
        N = read(), L = read(), R = read();
        for(reg int i = 1; i <= N; i ++) A[i] = read(), sum[i] = sum[i-1] + A[i];
        for(reg int i = 0; i <= N; i ++) sum[i] += N;
        memset(F, -0x3f, sizeof F); F[0] = 0;
        Build(1, 0, N<<1); Modify(1, 0);
        for(reg int i = L; i <= N; i ++){
                Lim = std::max(i-R, 0); 
                F[i] = std::max(F[i], Query(1, 0, std::max(0, sum[i]-1)) + 1);
                F[i] = std::max(F[i], Query(1, sum[i], sum[i]));
                F[i] = std::max(F[i], Query(1, std::min(sum[i]+1, N<<1), N<<1) - 1); 
                if(i-R >= 1) Del(1, i-R);
                if(i-L >= 0) Modify(1, i-L);
        }
        printf("%d\n", F[N]);
        return 0;
}

/*
Bug List:
1. Build -> push_up
2. For(int i = 1; i <= N; i ++)  <<-- For(int i = L; i <= N; i ++)
*/


posted @ 2019-06-23 23:09  XXX_Zbr  阅读(168)  评论(0编辑  收藏  举报