洛谷P12805 [AMPPZ 2019] Frogs
题面分析
题目其实就是:给出 \(n\) 段区间 \([l,r]\) 每段区间都有一个权值 \(s\),问在 \(1 \sim n\) 中哪个点覆盖该点的所有区间中权值最大的三个区间权值和最大,输出这个最大权值和。
关于具体实现
可以想到用类似单调队列的逻辑,依次遍历 \(1 \sim n\) 的每个点,由每段区间的 \([l,r]\) 决定其入队和出队顺序,维护在队列里的区间的权值。
容易想到可以用priority_queue和set分别维护该队列和队列里权值,在入队和出队的时候顺便在集合加入和删除元素。
需要注意的是,set不可重,可以用增加一个元素或者使用multiset解决。
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd() //快读
const int N = 2e5 + 5;
struct frog
{
int l,r,s,id;
bool operator < (const frog &x) const { return r > x.r; }
}f[N];
struct frog2
{
int l,r,s,id;
bool operator < (const frog2 &x) const { return (s == x.s) ? id < x.id : (s > x.s); }
};
int T,n;
bool cmp(frog x,frog y){ return x.l < y.l; }
signed main()
{
T = rd();
while(T--)
{
n = rd();
for(int i = 1;i <= n;i++)
{
int x = rd(),s = rd();
f[i] = {max(0,i - x),min(n,i + x),s,i};
}
sort(f + 1,f + n + 1,cmp);
priority_queue<frog> q;
set<frog2> ans;
int j = 1;
int res = 0;
for(int i = 1;i <= n;i++)
{
while(!q.empty() && q.top().r < i)
{
frog x = q.top();
ans.erase({x.l,x.r,x.s,x.id});
q.pop();
}
while(j <= n && f[j].l <= i)
{
q.push(f[j]);
ans.insert({f[j].l,f[j].r,f[j].s,f[j].id});
j++;
}
int k = 1;
auto it = ans.begin();
int cur = 0;
while(k <= 3)
{
if(ans.size() < 3) break;
cur += (*it).s;
it++;
k++;
}
res = max(res,cur);
}
cout << res << '\n';
}
return 0;
}

浙公网安备 33010602011771号