您的位置:首页 > 理论基础 > 数据结构算法

codeforces 191 E 数据结构题

2012-06-01 21:13 302 查看
题意,给你n个数,让你求第k大的连续区间和是多少

例如

3 4

1 4 2

最大的区间和 1 4 2

第二大 4 2

第三大 1 4

第四大即答案 4

首先要看出单调性:枚举的和越大,区间和大于它的区间数就越少

所以可以采用二分+树状数组统计的方法

二分答案,再n * log(n)判断有几个区间的区间和大于mid,然后调整上下界,使这个值不断的接近k。

判断符合条件的区间总数:线性扫描s【】(前n项和) 每次判断以i结尾的区间有几个区间和大于等于mid,累加即可

View Code

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: