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(); } }