题解十四:P14293 [JOI2024 预选赛 R2] 购物 2 / Shopping 2
题目。
思路
二分、前缀和。
对于每一次询问,我们可以先求出正常情况下从
前一部分很显然可以通过前缀和完成。
然后,我们开一个 vector 数组
每一次询问中,我们对于
代码
//846ms / 18.12MB / 950B C++17 O2
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,q,p[200010],d,l,r,ans;
struct node{
ll v,id;
};
vector<node> t[200010];
ll erfen(const vector<node>&y){//求折扣价
ll len=y.size();
if(len<=1) return 0;//如果这一天没有商品,就没有折扣
ll left=len,nl=1,nr=len-1,mid=0,right=0;
while(nl<=nr){//二分左端点
mid=(nl+nr)/2;
if(y[mid].id>=l)
left=mid,nr=mid-1;
else nl=mid+1;
}nl=1,nr=len-1;
while(nl<=nr){//二分右端点
mid=(nl+nr)/2;
if(y[mid].id<=r)
right=mid,nl=mid+1;
else nr=mid-1;
}if(left>right) return 0;//不存在
return (y[right].v-y[left-1].v)/2;//别忘了价格减半
}
int main(){
scanf("%lld%lld%lld",&n,&m,&q);
for(ll i=1;i<=m;i++) t[i].push_back({0,0});
for(ll i=1;i<=n;i++){
ll pp,a;
scanf("%lld%lld",&pp,&a);
t[a].push_back({pp,i});
p[i]=p[i-1]+pp;//计算前缀和
}for(ll i=1;i<=m;i++){
for(ll j=2;j<t[i].size();j++)
t[i][j].v+=t[i][j-1].v;//依旧前缀和
}while(q--){
scanf("%lld%lld%lld",&d,&l,&r);
ans=p[r]-p[l-1];
printf("%lld\n",ans-erfen(t[d]));
}return 0;
}