博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

Codechef August Challenge 2018 : Coordinate Compression

传送门

外边二分,里面拿线段树维护贪心就行了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define MN 110000
#define lp p<<1
#define rp p<<1|1 
using namespace std;

vector<int> v[MN];
int t,n,s,a[MN],o[MN],z[MN<<2];
bool cmp(int x,int y){return a[x]==a[y]?x<y:a[x]<a[y];}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
void add(int p,int l,int r,int k,int v){
    z[p]=max(z[p],v);
    if (l==r) return;
    int mid=l+r>>1;
    if (k<=mid) add(lp,l,mid,k,v);else add(rp,mid+1,r,k,v);
}
int ask(int p,int l,int r,int L,int R){
    if (l==L&&r==R) return z[p];
    int mid=l+r>>1;
    if (R<=mid) return ask(lp,l,mid,L,R);else
    if (L>mid) return ask(rp,mid+1,r,L,R);else
    return max(ask(lp,l,mid,L,mid),ask(rp,mid+1,r,mid+1,R));
}
inline bool ju(int k){
    long long o=0;
    int la=0,e=0;
    memset(z,0,(n+5)*16);
    for (int i=0;v[i].size();i++){
        for (int j=0;j<v[i].size();){
            int w,m;
            for (w=j+1;w<v[i].size();w++)
            if (v[i][w]-v[i][w-1]>k) break;
            m=ask(1,1,n,max(1,v[i][j]-k),min(n,v[i][w-1]+k))+1;
            for (;j!=w;j++)    o+=m,add(1,1,n,v[i][j],m);
        }
    }
    return o<=s;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&s);
        for (int i=0;i<n;i++) scanf("%d",&a[i]),o[i]=i;
        sort(o,o+n,cmp);v[0].push_back(o[0]+1);
        for (int i=1,j=0;i<n;i++) j+=a[o[i]]!=a[o[i-1]],v[j].push_back(o[i]+1);
        int l=0,r=n;
        while (l<r){
            int mid=l+r+1>>1;
            if (ju(mid)) l=mid;else r=mid-1;
        }
        printf("%d\n",ju(l)?l+1:0);
        for (int i=0;i<n;i++) v[i].clear();
    }
}
View Code

 

posted @ 2018-08-17 16:14  swm_sxt  阅读(270)  评论(0编辑  收藏  举报