Luogu2772

Update

  • 20210219 标点改为了全角

由题意,最后若 \(x_1<x_2\),则 \(y_1>y_2\),即具有单调性。

好像是单调队列?由于对谔谔的单调队列的憎恶,我们尝试使用别的解法。

考虑使用我在这篇博客里讲到的算法解决。

答案显然是单调的(上面分析过),因此我们考虑通过归并得到答案。

归并操作就很显然了(见代码),注意在归并过程中删去不合适的点。

\(k\) 次加点操作在末尾加入一个长度为一的块,然后在末尾进行 \(\log_2\operatorname{lowbit}k\) 次归并,这样就是一个二进制拆分。

通过树状数组的知识,我们可以显然证明这个算法复杂度是 \(O(n\log n)\) 的。

看代码感性理解一下吧(由于大量使用STL,常数很大,因此最好配合一个O2优化)。

Code:

#include <stack>
#include <stdio.h>
#include <vector>
typedef unsigned long long ullt;
typedef unsigned uint;
typedef long long llt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
typedef std::pair<uint,uint>P;
std::vector<std::vector<P> >V;
std::vector<P>User;
bol _union()
{
    if(V.size()<=1)return false;
    std::stack<P>S1,S2;P p;
    while(!V.back().empty())S1.push(V.back().back()),V.back().pop_back();
    V.pop_back();
    while(!V.back().empty())S2.push(V.back().back()),V.back().pop_back();
    while(!(S1.empty()&&S2.empty()))
    {
        if(S2.empty())p=S1.top(),S1.pop();
        else if(S1.empty()||S2.top()<S1.top())p=S2.top(),S2.pop();
        else p=S1.top(),S1.pop();
        while(!V.back().empty()&&V.back().back().second<=p.second)V.back().pop_back();
        V.back().push_back(p);
    }
    return true;
}
int main()
{
    uint n,k;scanf("%u",&n);
    User.push_back(P(0,0));
    for(uint i=1;i<=n;i++)
    {
        scanf("%u%u",&User[0].first,&User[0].second),V.push_back(User),k=i&-i;
        while(k>>=1)_union();
    }
    while(_union());User=V[0],k=User.size();
    for(uint i=0;i<k;i++)
    {
        if(i)putchar(',');
        printf("(%u,%u)",User[i].first,User[i].second);
    }
	return 0;
}

posted @ 2022-02-14 06:59  myee  阅读(52)  评论(0)    收藏  举报