• bzoj2006: [NOI2010]超级钢琴(主席树+优先队列)


    bzoj2006: [NOI2010]超级钢琴

    bzoj2006: 超级钢琴

    思路

    对所有前缀和建权值线段树,先将所有右端点对应的最大的左端点丢进优先队列里,每次将优先队列队首的区间取出来后,将rk[r]++,从这个右端点对应的主席树区间中找到排名第rk[r]的值丢进优先队列,相当于用主席树求区间第k小。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    #define dd(x) cout<<#x<<"="<<x<<" "
    #define rep(i,a,b) for(int i=(a);i<(b);i++)
    #define de(x) cout<<#x<<"="<<x<<"
    "
    #define mes(p) memset(p,0,sizeof(p))
    #define fi first
    #define se second
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    #define sz(x) (int)x.size()
    #define pb push_back
    #define ls (rt<<1)
    #define rs (ls|1)
    #define all(x) x.begin(),x.end()
    const int maxn=500005;
    typedef long long ll;
    typedef vector <int > vi;
    typedef pair <int, int> pi;
    int n,k,L,R, cnt;
    ll a[maxn], s[maxn];
    int T[maxn], rk[maxn];
    vector<ll > v;
    struct tr{
        int sum,l,r;
    }t[maxn<<5];
    struct node {
        ll s;
        int t;
        node (){}
        node(ll _s,int _t){
            s=_s, t=_t;
        }
        bool operator < (const node& a) const{
            return s<a.s;
        }
    };
    priority_queue<node> q;
    void update(int pre,int &now,int l,int r,int pos){
        now = ++ cnt;
        t[now].sum = t[pre].sum+1;
        if(l==r) return ;
        t[now].l=t[pre].l;
        t[now].r=t[pre].r;
        int mid = l+r>>1;
        if(pos<=mid) update(t[pre].l,t[now].l,l,mid,pos);
        else update(t[pre].r,t[now].r,mid+1,r,pos);
    }
    int qr(int x,int y,int l,int r,int k){
        if(l==r) return l;
        int mid = l+r>>1;
        int sl = t[t[y].l].sum - t[t[x].l].sum;
        if(sl>=k) return qr(t[x].l,t[y].l,l,mid,k);
        else return qr(t[x].r,t[y].r,mid+1,r,k-sl);
    }
    int main(){
        scanf("%d%d%d%d",&n,&k,&L,&R);
        rep(i,1,n+1) cin>>a[i], s[i]=s[i-1]+a[i],v.pb(s[i]);
        v.pb(0);
        sort(all(v));
        v.erase(unique(all(v)),v.end());
        int m= sz(v);
        update(T[0],T[1],1,m,lower_bound(all(v),0)-v.begin()+1);
        rep(i,2,n+2){
            update(T[i-1],T[i],1,m,lower_bound(all(v),s[i-1])-v.begin()+1);
            int l=max(1,i-R), r=i-L;
            if(r<=0) continue;
            int ss = qr(T[l-1],T[r],1,m,1);
            q.push(node(s[i-1]-v[ss-1],i));
            rk[i-1]=1;
        }
        ll ans = 0;
        while(k--){
            ans += q.top().s;
            int x=q.top().t;
            q.pop();
            int l=max(1,x-R), r=x-L, ss;
            ++rk[x-1];
            if(rk[x-1]>t[T[r]].sum-t[T[l-1]].sum) continue;
            ss = qr(T[l-1],T[r],1,m,rk[x-1]);
            q.push(node(s[x-1]-v[ss-1],x));
        }
        printf("%lld",ans); 
        return 0;
    }
    
  • 相关阅读:
    Android开发技术周报 Issue#39
    Android开发技术周报 Issue#40
    Android开发技术周报 Issue#41
    js删除最后一个字符串方法
    Firefox 插件 JSview是一套比较实用的JS,CSS文件查看工具,很方便,很快捷地查看页面引用了哪些文件,作为Web前端开发者是一套必备的插件,由于Firefox升级过快,插件很快不兼容了,这里对插件做了一些调整,可以兼容最新Firefox浏览器(目前FireFox 21)
    IT人常用的网站
    Jquery,全选,反选,
    Vue.js基础(二)
    Vue.js基础(一)
    Vue.js模拟百度下拉框
  • 原文地址:https://www.cnblogs.com/seast90/p/10836220.html
Copyright © 2020-2023  润新知