题目链接(正睿)
题目大意
给出\(n\)个活动和每个活动的吸引力和开始和结束时间,总天数为\(D\)。规定一天最多参加\(k\)个活动,求哪一天的吸引力总和最大。
\(1\le n \le 3 \times 10^5,~1 \le D \le 3\times 10^5\)
## 分析
将所有开始、结束的时间标记一下,使用\(\text{set}\)动态维护每个时间点吸引力前\(k\)大的和。具体地,记录每一个时间点第\(k\)大的数\(knum\)是多少,如果现在要插入的数比\(knum\)大,那么插入该数字,\(knum\)左移一位,否则不用管\(knum\),最后维护一下前缀和即可。删除数字是把这个过程逆过来即可。
实现
主要部分就是动态维护\(\text{set}\)的过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| while(!a[i].empty()){ ll cur=a[i].front();a[i].pop(); q.insert(cur); if(q.size()<=k) itk=q.end(),itk--,sum+=cur; else if(cur>*itk) sum-=*itk,itk--,sum+=cur; } maxn=max(maxn,sum); while(!b[i].empty()){ ll cur=b[i].front();b[i].pop(); auto p=q.find(cur); if(q.size()<=k) sum-=cur; else if(cur>=*itk) itk++,sum-=cur,sum+=*itk; q.erase(p); }
|
附完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include<bits/stdc++.h> #define ll long long using namespace std; const ll N=300005; ll h,s,e,maxn,n,t,d,k,sum; multiset<ll, greater<ll> > q; queue<ll> a[N],b[N]; int main(){ ios::sync_with_stdio(false); cin>>t; for(int cas=1;cas<=t;cas++){ maxn=sum=0;auto itk=q.end(); cin>>d>>n>>k; for(int i=1;i<=n;i++){ cin>>h>>s>>e; a[s].push(h);b[e].push(h); } for(int i=1;i<=d;i++){ while(!a[i].empty()){ ll cur=a[i].front();a[i].pop(); q.insert(cur); if(q.size()<=k) itk=q.end(),itk--,sum+=cur; else if(cur>*itk) sum-=*itk,itk--,sum+=cur; } maxn=max(maxn,sum); while(!b[i].empty()){ ll cur=b[i].front();b[i].pop(); auto p=q.find(cur); if(q.size()<=k) sum-=cur; else if(cur>=*itk) itk++,sum-=cur,sum+=*itk; q.erase(p); } } printf("Case #%d: %lld\n",cas,maxn); } return 0; }
|