zoukankan      html  css  js  c++  java
  • [线段树][ST表][堆]luogu P5967 [POI2016]Korale

    题面

    https://www.luogu.com.cn/problem/P5967

    分析

    看这种可以线性扩展且要求第 k 小的问题,就容易想到超级钢琴的做法

    初始将一个 (a[1],1) 加入小根堆 (sum,i) ,每次取出堆顶时可以扩展为 (sum+a[i+1],i+1) , (sum-a[i]+a[i+1],i+1) (i<n) 显然取出到第 k 个时即为第 k 小(k 预先减 1 除去 0 的情况)

    那么考虑大小相同的情况,我们用一个 cnt 来记录

    因为要求字典序最小,所以搜索的时候贪心地选择靠前的且小于当前值 sum 的,可以用线段树或者 ST表 来维护这个最小值

    ST表占用内存过高,会影响运行速度,最后用的线段树

    代码

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int Inf=1e9+1;
    const int N=1e6+10;
    struct Sum {
        ll val;int id;
        friend bool operator < (Sum a,Sum b) {return a.val>b.val;}
    };
    int n,k,m,same,pw[20],lg2[N],a[N],f[N][20];
    ll ans;
    priority_queue<Sum>q;
    int s[N],top;
    bool fin;
    
    inline int read(){
        register int s=0,w=1;
        char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    
    inline void write(int x) {
        if(x>9) write(x/10);putchar(x%10+48);return;
    }
    
    inline int Min(int l,int r) {return min(f[l][lg2[r-l+1]],f[r-pw[lg2[r-l+1]]+1][lg2[r-l+1]]);}
    
    inline void DFS(int dep,ll sum) {
        if (!sum) {
            same--;
            if (!same) {
                for (register int i=1;i<=top;i++) write(s[i]),putchar(32);
                fin=1;
            }
            return;
        }
        if (dep>n) return;
        for (register int i=dep;i<=n;i++) {
            register int l=i,r=n;
            while (l<=r) {
                register int mid=l+r>>1;
                if (Min(l,mid)<=sum) i=mid,r=mid-1;
                else l=mid+1;
            }
            if (!i) return;
            s[++top]=i;DFS(i+1,sum-f[i][0]);
            top--;if (fin) return;
        }
    }
    
    int main() {
        n=read(),k=read();m=log2(n);
        pw[0]=1;for (register int i=1;i<=m;i++) pw[i]=pw[i-1]<<1;
        for (register int i=1,j=0;i<=n;i++) a[i]=read(),f[i][0]=a[i],lg2[i]=j,j+=(i==pw[j]);
        for (register int i=1;i<=m;i++)
            for (register int j=1;j+pw[i]-1<=n;j++) f[j][i]=min(f[j][i-1],f[j+pw[i-1]][i-1]);
        sort(a+1,a+n+1);q.push((Sum){a[1],1});
        same=1;ans=0;
        for (register int i=1;i<k;i++) {
            register Sum now=q.top();q.pop();
            if (now.val>ans) ans=now.val,same=0;
            if (now.val==ans) same++;
            if (now.id<n) q.push((Sum){now.val-a[now.id]+a[now.id+1],now.id+1}),q.push((Sum){now.val+a[now.id+1],now.id+1});
        }
        printf("%lld
    ",ans);
        DFS(1,ans);
    }
    ST表版
    //ST占内存太高过不了 
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #define lson (x<<1)
    #define rson ((x<<1)+1)
    using namespace std;
    typedef long long ll;
    const int Inf=1e9+1;
    const int N=1e6+10;
    struct Sum {
        ll val;int id;
        friend bool operator < (Sum a,Sum b) {return a.val>b.val;}
    };
    int n,k,m,same,a[N],t[4*N],rev[N];
    ll ans;
    priority_queue<Sum>q;
    int s[N],top;
    bool fin;
    
    inline int read(){
        register int s=0,w=1;
        char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    
    inline void write(int x) {
        if(x>9) write(x/10);putchar(x%10+48);return;
    }
    
    inline void Build(int x,int l,int r) {
        if (l==r) {t[rev[l]=x]=a[l];return;}
        int mid=l+r>>1;
        Build(lson,l,mid);Build(rson,mid+1,r);
        t[x]=min(t[lson],t[rson]);
    }
    
    inline int Query(int x,int l,int r,int k,ll lim) {
        if (k<=l) {
            if (t[x]>lim) return 0;
            if (l==r) return l;
        }
        int mid=l+r>>1,lef=0;
        if (k<=mid) lef=Query(lson,l,mid,k,lim);
        if (lef) return lef;
        return Query(rson,mid+1,r,k,lim);
    }
    
    inline void DFS(int dep,ll sum) {
        if (!sum) {
            same--;
            if (!same) {
                for (register int i=1;i<=top;i++) write(s[i]),putchar(32);
                fin=1;
            }
            return;
        }
        if (dep>n) return;
        for (register int i=dep;i<=n;i++) {
            if (!(i=Query(1,1,n,i,sum))) return;
            s[++top]=i;DFS(i+1,sum-t[rev[i]]);
            top--;if (fin) return;
        }
    }
    
    int main() {
        n=read(),k=read();
        for (register int i=1,j=0;i<=n;i++) a[i]=read();
        Build(1,1,n);sort(a+1,a+n+1);q.push((Sum){a[1],1});
        same=1;ans=0;
        for (register int i=1;i<k;i++) {
            register Sum now=q.top();q.pop();
            if (now.val>ans) ans=now.val,same=0;
            if (now.val==ans) same++;
            if (now.id<n) q.push((Sum){now.val-a[now.id]+a[now.id+1],now.id+1}),q.push((Sum){now.val+a[now.id+1],now.id+1});
        }
        printf("%lld
    ",ans);
        DFS(1,ans);
    }
    线段树版
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/mastervan/p/14578854.html
Copyright © 2011-2022 走看看