【JZOJ A组】Melancholy

Description

DX3906星系,Melancholy星上,我在勘测这里的地质情况。
我把这些天来已探测到的区域分为N组,并用二元组(D,V)对每一组进行标记:其中D为区域的相对距离,V为内部地质元素的相对丰富程度。
在我的日程安排表上有Q项指派的计划。每项计划的形式是类似的,都是“对相对距离D在[L,R]之间的区域进行进一步的勘测,并在其中有次序地挑出K块区域的样本进行研究。”采集这K块的样品后,接下来在实验中,它们的研究价值即为这K块区域地质相对丰富程度V的乘积。
我对这Q项计划都进行了评估:一项计划的评估值P为所有可能选取情况的研究价值之和。
但是由于仪器的原因,在一次勘测中,这其中V最小的区域永远不会被选取。
现在我只想知道这Q项计划的评估值对2^32取模后的值,特殊地,如果没有K块区域可供选择,评估值为0。

Input

第一行给出两个整数,区域数N与计划数Q。
第二行给出N个整数,代表每一块区域的相对距离D。
第三行给出N个整数,代表每一块区域的内部地质元素的相对丰富程度V。
接下来的Q行,每一行3个整数,代表相对距离的限制L,R,以及选取的块数K。

Output

输出包括Q行,每一行一个整数,代表这项计划的评估值对2^32取模后的值。

Sample Input

5 3
5 4 7 2 6
1 4 5 3 2
6 7 1
2 6 2
1 8 3

Sample Output

5
52
924

Data Constraint

在这里插入图片描述

思路

发现k不大,而且是个区间问题,不妨考虑线段树。

线段树维护区间最小值和区间k=1…6的答案

合并时f[k]=f[i]*f[k-j]

代码

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef unsigned int u32;

const int maxn=1000005;
const u32 inf=4294967295u;

int n,q;
int k;
struct node
{
		u32 d,v;
}a[maxn],L,R;
bool cmp(const node &a,const node &b) {return a.d < b.d;}

struct power
{
	u32 val[7];
	friend power operator +(power a,power b)
	{
		power c;
		for(int i=1; i<=6; i++) c.val[i]=a.val[i]+b.val[i];
		for(int i=1; i<=6; i++)
			for(int j=1; j < i; j++)
				c.val[i] += a.val[j]*b.val[i-j];
		return c;
	}
}Node[maxn],A[3],Ans;

struct Min
{
	u32 val,pos;
	friend Min operator +(Min a,Min b)
	{
		Min c=(Min){inf,0};
		if(a.val < c.val) c=a;
		if(b.val < c.val) c=b;
		return c;
	}
}Val[maxn],res_min;


void build(int i,int l,int r)
{
	Val[i]=(Min){inf,0};
	for(int j=1; j<=6; j++) Node[i].val[j]=0;
	if(l == r)
	{
		Node[i].val[1]=a[l].v;
		Val[i]=(Min){a[l].v,l};
		return;
	}
	int mid=l+r >> 1;
	build(i << 1,l,mid); build(i << 1 | 1,mid+1,r);
	Node[i]=Node[i << 1]+Node[i << 1 | 1];
	Val[i]=Val[i << 1]+Val[i << 1 | 1];
}

void find(int i,int l,int r,int L,int R)
{
	if(L>R) return;
	if(L<=l&&r<=R)
	{
		res_min=res_min+Val[i];
		return;
	}
	int mid=l+r >> 1;
	if(L<=mid) find(i << 1,l,mid,L,R);
	if(mid+1<=R) find(i << 1 | 1,mid+1,r,L,R);
}

void query(int i,int l,int r,int L,int R,int opt)
{
	if(L>R) return;
	if(L<=l&&r<=R)
	{
		A[opt]=A[opt]+Node[i];
		return;
	}
	int mid=l+r>>1;
	if(L<=mid) query(i<<1,l,mid,L,R,opt);
	if(mid+1<=R) query(i<<1|1,mid+1,r,L,R,opt);
}


void solve(int k)
{
	int LL=lower_bound(a+1,a+n+1,L,cmp)-a;
	int RR=upper_bound(a+1,a+n+1,R,cmp)-a-1;
	if(LL>=RR) {printf("0\n"); return;}

	res_min=(Min){inf,0};
	find(1,1,n,LL,RR);

	for(int i=1; i<=6; i++) A[1].val[i]=A[2].val[i]=0;
	query(1,1,n,LL,res_min.pos-1,1);
	query(1,1,n,res_min.pos+1,RR,2);

	Ans=A[1]+A[2];
	for(u32 i=1; i<=k; i++) Ans.val[k]*=i;
	printf("%u\n",Ans.val[k]);
}

int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1; i<=n; i++) scanf("%u",&a[i].d);
	for(int i=1; i<=n; i++) scanf("%u",&a[i].v);
	sort(a+1,a+n+1,cmp);

	build(1,1,n);
	
	while(q--)
	{
		scanf("%u%u%u",&L.d,&R.d,&k);
		solve(k);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值