洛谷P12805 [AMPPZ 2019] Frogs

题面分析

题目其实就是:给出 \(n\) 段区间 \([l,r]\) 每段区间都有一个权值 \(s\),问在 \(1 \sim n\) 中哪个点覆盖该点的所有区间中权值最大的三个区间权值和最大,输出这个最大权值和。

关于具体实现

可以想到用类似单调队列的逻辑,依次遍历 \(1 \sim n\) 的每个点,由每段区间的 \([l,r]\) 决定其入队和出队顺序,维护在队列里的区间的权值。

容易想到可以用priority_queueset分别维护该队列和队列里权值,在入队和出队的时候顺便在集合加入和删除元素。

需要注意的是,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;
}
posted @ 2025-07-10 17:49  IC0CI  阅读(11)  评论(0)    收藏  举报