zoukankan      html  css  js  c++  java
  • hdu 6058 并查集

    题意: 给你一个全排列,要你求这个序列的所有区间的第k大的和

    思路:一道链表好题。。虽然没用链表做。。这两天有机会用链表补一下。。

      拿到题首先分析数据性质,一个是全排列,一个是k比较小,因此我们可以考虑维护每个点周围比这个点向左大0--k-1的数有多少和向右。(相当于枚举这个点作为第K大的区间有多少个),这里注意的是要跳过比枚举点要小的数,如果可以o1跳过,那么单个点维护就是o(k)的复杂度。这里使用了并查集,慢于o1不过也莽过去了。。。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define MEM(a,b) memset(a,b,sizeof(a))
    #define PB push_back
    #define MP make_pair
    #define X first
    #define Y second
    #define bug puts("bug");
    typedef long long ll;
    const int maxn=1e6+10;
    int t,n,k,x;
    ll ans;
    int a[maxn],c[maxn],O[maxn],fa[maxn],L[maxn],R[maxn];
    
    int fin(int x){
        if(fa[x]==x) return x;
        return fa[x]=fin(fa[x]);
    }
    
    void update(int x,int y){
        int fx=fin(x),fy=fin(y);
        fa[fx]=fy;
        R[fy]=max(R[fy],R[fx]),L[fy]=min(L[fy],L[fx]);
    }
    void sl(int x){
        vector<ll> lk(k+1,x+1),rk(k+1,x-1);
        int lid=x,rid=x;
        int mk1=0,mk2=0;
        for(int i=0;i<k&&lid>0;i++){
            mk1=max(mk1,i);
            lid=L[fin(lid)];
            if(lid>0&&O[lid]==0&&O[lid-1]) lid=L[fin(lid-1)];
            lk[i]=lid;
            lid--;
        }
        for(int i=0;i<k&&rid<=n;i++){
            mk2=max(mk2,i);
            rid=R[fin(rid)];
            if(rid<=n&&O[rid]==0&&O[rid+1]) rid=R[fin(rid+1)];
            rk[i]=rid;
            rid++;
        }
        int ll=x+1,rr=x-1;
        for(int i=0;i<k;i++){
            if(i>mk1||(k-i-1)>mk2) continue;
            ll=x+1,rr=x-1;
            if(i!=0) ll=lk[i-1];
            if(k-i-1!=0)rr=rk[k-i-2];
            ans+=(abs(lk[i]-ll))*(abs(rk[k-i-1]-rr))*c[x];
        }
    }
    
    void modi(int x){
        O[x]=1;
        if(x-1>0&&O[x-1])update(x,x-1);
        if(x+1<=n&&O[x+1])update(x,x+1);
    }
    
    int main(){
        scanf("%d",&t);
        while(t--){
            ans=0;
            MEM(O,0);
            scanf("%d%d",&n,&k);
            for(int i=1;i<=n;i++) fa[i]=L[i]=R[i]=i;
            for(int i=1;i<=n;i++) scanf("%d",&c[i]),a[c[i]]=i;
            for(int i=1;i<=n;i++){
                modi(a[i]);
                if(i<=n-k+1) sl(a[i]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    



  • 相关阅读:
    201521123093 java 第二周学习总结
    201521123093 java 第一周总结
    Word 2010怎么自动添加文献引用
    动态链接库(dll)文件的动态调用(使用动态链接库,解析Wis文件--测井数据文件的一种)
    open inventor 学习笔记
    井眼轨迹的三次样条插值 (vs + QT + coin3d)
    VS2010 + QT 5 +open inventor 环境配置
    我的第一个项目(人力资源管理之报表管理)
    B-tree 和 B+tree
    mysql count(*)与count(1)的区别
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672509.html
Copyright © 2011-2022 走看看