ABC391D题解

前置知识:

  • map
  • priority_queue

思路

考虑预处理每一个图块在第几秒后会被删除。

如何预处理?我使用了一种非常暴力的做法,首先处理的过程肯定是从下往上的,于是每一个图块能被删除一定是它对应的每一列都至少有一个图块,而且每次我们肯定都是选择这个图块对应的每一列的离最下面最近的图块去拼成一个全满的形态,然后消消乐,第几秒才能达到全满的形态呢?自然就是选择的图块中离最下面最远的点的高度,每一次选完后都把这些点删掉。

步骤

一开始用一个 map 记录每个坐标是哪个图块,用优先队列存储所有坐标中列数是这个列的所有行,按升序排序,一开始让所有列全部放入另一个 map,对于 map 中的元素 \(i\),取出第 \(i\) 个优先队列的队首,如果这个队列空了,那就在这第二个 map 中删掉这个元素,然后秒数就是每一个元素取出的队首中的最大值,至于为什么需要第二个 map,是因为如果这样每次都遍历所有列,时间复杂度会超,所以需要一个 map 时时删除不需要遍历的列。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
map<pair<int,int>,int>mp;
int num[N];
priority_queue<int,vector<int>,greater<int>>q[N];
map<int,int>mp1;
signed main()
{
    int n,w;
    scanf("%d %d",&n,&w);
    for(int i = 1;i<=n;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        swap(x,y);
        mp[{x,y}] = i;
        if(mp1.find(y) == mp1.end())
        {
            mp1[y] = 1;
        }
        q[y].push(x);
    }
    while(mp1.size())
    {
        int maxx = 0;
        if(mp1.size() == w)//如果可以组成全满形态
        {
            for(auto it = mp1.begin();it!=mp1.end();it++)
            {
                int y = it->first;
                int x = q[y].top();
                maxx = max(maxx,x);
            }
        }
        else
        {
            maxx = 2e9;//如果不能组成全满形态,那么选出的这些图块就不会被删
        }
        for(auto it = mp1.begin();it!=mp1.end();)
        {
            int y = it->first;
            int x = q[y].top();
            q[y].pop();
            num[mp[{x,y}]] = maxx;
            if(!q[y].size())
            {
                it = mp1.erase(it);
            }
            else
            {
                it++;
            }
        }
    }
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        if(x>=num[y])
        {
            printf("No\n");
        }
        else
        {
            printf("Yes\n");
        }
    }
    return 0;
}
posted @ 2025-02-11 22:00  林晋堃  阅读(39)  评论(0)    收藏  举报