https://ac.nowcoder.com/acm/contest/900/B
给定一个长度为 n n n的序列,要求对于每一个连续的长度为 m m m的区间,求前 k k k大数的和
n , m ≤ 1 0 5 n,m\leq 10^5 n,m≤105
一眼正解。。。权值线段树,先插入m个数,然后用类似询问第 k k k大的过程,如果往右区间走了说明k比所有左区间的数都大,那么我们可以直接加上左区间所有数的和,这个玩意儿我们可以开数组维护
然鹅。。。
少开一个 l o n g l o n g long\ long long long少10分,队友报错数据范围痛失60分。。。
气啊啊啊啊啊啊啊啊!!!!
从rk10掉到rk32
备注:以下代码和比赛打的代码差异较大
改了的地方主要是把增加和删除合并到一起,上传方式改变了一下,如果对线段树操作有疑问的,可以去看本菜鸡的博客一些关于线段树的操作记录
#include
#include
#include
#define N 400010
#define maxn 100000
#define lson k<<1
#define rson k<<1|1
using namespace std;int sum[N],n,m,k,a[maxn+10];
long long prosum[N],ans;
inline long long read()
{
char c;int d=1;long long f=0;
while(c=getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void add(int x,int d,int l=0,int r=maxn,int k=1)
{
sum[k]+=d;prosum[k]+=x*d;
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) add(x,d,l,mid,lson);
else add(x,d,mid+1,r,rson);
return;
}
inline void kth(int p,int l=0,int r=maxn,int k=1)
{
if(l==r) {ans+=(long long)l*p;return;}
int s=sum[lson],mid=l+r>>1;
if(s>=p) {kth(p,l,mid,lson);return;}
ans+=prosum[lson];kth(p-s,mid+1,r,rson);return;
}
signed main()
{
n=read();m=read();k=read();
for(register int i=1;i<=m;i++) a[i]=read(),add(a[i],1);
kth(k);
for(register int i=m+1;i<=n;i++)
{
a[i]=read();
add(a[i],1);add(a[i-m],-1);kth(k);
}
printf("%lld",ans);
}