牛客OI周赛10-提高组 T2 Taeyeon的困惑

链接

https://ac.nowcoder.com/acm/contest/900/B


D e s c r i p t i o n Description Description

给定一个长度为 n n n的序列,要求对于每一个连续的长度为 m m m的区间,求前 k k k大数的和

n , m ≤ 1 0 5 n,m\leq 10^5 n,m105


S o l u t i o n Solution Solution

一眼正解。。。权值线段树,先插入m个数,然后用类似询问第 k k k大的过程,如果往右区间走了说明k比所有左区间的数都大,那么我们可以直接加上左区间所有数的和,这个玩意儿我们可以开数组维护

然鹅。。。

少开一个 l o n g   l o n g long\ long long long少10分,队友报错数据范围痛失60分。。。

气啊啊啊啊啊啊啊啊!!!!

从rk10掉到rk32


备注:以下代码和比赛打的代码差异较大
改了的地方主要是把增加和删除合并到一起,上传方式改变了一下,如果对线段树操作有疑问的,可以去看本菜鸡的博客一些关于线段树的操作记录

C o d e Code Code

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

你可能感兴趣的:(权值线段树,权值线段树,Taeyeon的困惑)