codeforces 191 E 数据结构题
题意,给你n个数,让你求第k大的连续区间和是多少
例如
3 4
1 4 2
最大的区间和 1 4 2
第二大 4 2
第三大 1 4
第四大即答案 4
首先要看出单调性:枚举的和越大,区间和大于它的区间数就越少
所以可以采用二分+树状数组统计的方法
二分答案,再n * log(n)判断有几个区间的区间和大于mid,然后调整上下界,使这个值不断的接近k。
判断符合条件的区间总数:线性扫描s【】(前n项和) 每次判断以i结尾的区间有几个区间和大于等于mid,累加即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define clr(x,what) memset(x,what,sizeof(x)); typedef __int64 lld; const int maxn = 100010; const lld inf = 1e9 ; int c[maxn]; lld s[maxn],num[maxn]; int n,tot; void update(int x,int d){ for(;x<maxn;x+=x&-x) c[x]+=d; } int sum(int x){ int ans=0; for(;x>0;x-=x&-x) ans+=c[x]; return ans; } lld calc(lld mid){ lld ans=0; clr(c,0); for(int i=1;i<=n;i++){ if(s[i]>=mid) ans++; lld x=s[i]-mid; int id=upper_bound(num+1,num+tot+1,x)-num-1; int id2=lower_bound(num+1,num+tot+1,s[i])-num; ans+=sum(id); update(id2,1); } return ans; } int main(){ int i,j,k; lld m; scanf("%d%I64d",&n,&m); for(i=1;i<=n;i++){ scanf("%I64d",&s[i]); s[i]+=s[i-1]; num[i]=s[i]; } sort(num+1,num+n+1); tot=unique(num+1,num+n+1)-num-1; lld l=-inf*lld(n),r=inf*lld(n),mid,best=-1; while(l<=r){ mid=(l+r)/2; if(calc(mid)>=m){ best=mid; l=mid+1; } else r=mid-1; } printf("%I64d\n",best); return 0; }
copy了“红”牛的平衡树代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <string> #include <vector> #include <set> #include <map> #include <queue> using namespace std; #define lowbit(x) ((x)&(-(x))) #define sqr(x) ((x)*(x)) #define PB push_back #define MP make_pair typedef unsigned long long ULL; typedef long long LL; typedef vector<int> VI; typedef vector<string> VS; typedef pair<int,int> PII; struct Tpoint { double x,y; Tpoint(){} Tpoint(double _x,double _y){x=_x;y=_y;} inline void read(){scanf("%lf%lf",&x,&y);} inline void show(){printf("%lf %lf\n",x,y);} inline double norm(){ return sqrt( sqr(x)+sqr(y) ); } }; inline Tpoint operator +(const Tpoint &a,const Tpoint &b){ return Tpoint(a.x+b.x,a.y+b.y); } inline Tpoint operator -(const Tpoint &a,const Tpoint &b){ return Tpoint(a.x-b.x,a.y-b.y); } inline Tpoint operator *(const Tpoint &a,const double &b){ return Tpoint(a.x*b,a.y*b); } inline Tpoint operator /(const Tpoint &a,const double &b){ return Tpoint(a.x/b,a.y/b); } inline double det(const Tpoint &a,const Tpoint &b){ return a.x*b.y-a.y*b.x; } inline double dot(const Tpoint &a,const Tpoint &b){ return a.x*b.x+a.y*b.y; } //============================================================================================= const int maxn = 100005; const long long inf = 1000000000000000LL; struct node { int left,right,aux,cnt,size; long long key; }tree[maxn]; int n,a[maxn],tot; long long s[maxn]; inline void init() { tot=0; tree[0].left=tree[0].right=tree[0].cnt=tree[0].size=0; tree[0].aux=(RAND_MAX<<14)+RAND_MAX+1; } inline void renew(int &root) { tree[root].size=tree[root].cnt+tree[tree[root].left].size+tree[tree[root].right].size; } inline void leftRotate(int &root) { int t=tree[root].left; tree[root].left=tree[t].right; tree[t].right=root; renew(root); renew(t); root=t; } inline void rightRotate(int &root) { int t=tree[root].right; tree[root].right=tree[t].left; tree[t].left=root; renew(root); renew(t); root=t; } inline void insert(int &root,long long key) { if (root==0){ root=++tot; tree[root].left=tree[root].right=0; tree[root].cnt=tree[root].size=1; tree[root].key=key; tree[root].aux=(rand()<<14)+rand(); return; } if (tree[root].key==key){ ++tree[root].cnt; }else if (key<tree[root].key){ insert(tree[root].left,key); if (tree[tree[root].left].aux<tree[root].aux) leftRotate(root); }else{ insert(tree[root].right,key); if (tree[tree[root].right].aux<tree[root].aux) rightRotate(root); } renew(root); } inline int getNum(int &root,long long key) { if (root==0) return 0; if (tree[root].key>key) return getNum(tree[root].left,key); return tree[root].cnt+tree[tree[root].left].size+getNum(tree[root].right,key); } inline long long calc(long long limit) { init(); int root=0; insert(root,s[0]); long long ret=0; for (int i=1;i<=n;++i){ long long x=s[i]-limit; ret+=getNum(root,x); insert(root,s[i]); } return ret; } int main() { long long k; scanf("%d%I64d",&n,&k); for (int i=0;i<n;++i){ scanf("%d",&a[i]); s[i+1]=s[i]+a[i]; } LL l=-1,r=inf*2; while (l+1<r){ LL mid=(l+r)/2; if (calc(mid-inf)>=k) l=mid; else r=mid; } printf("%I64d\n",l-inf); return 0; }