Trace(思维or数据结构)

传送门

题意不多做说明了。

本题有一个很关键的条件就是不存在两个矩形,一个矩形能完全包含另一个矩形。这决定了每一个输入的矩形都会对答案有贡献。考虑到输入的矩形可能会被后面的矩形覆盖。所以我们需要逆向更新答案。

最后输入的矩形一定不会被任何矩形覆盖,所以直接加入答案。往前询问每一个矩形时,仅以x方向上的边举例,询问它后面的矩形里x比它小的最大值,用它的x大小减去这个最大值就是它的x边对于答案的贡献。因为x比它大的矩形里,y都会比它小,想象一下,这些矩形不会影响到它的x对于答案的贡献。

如果它后面矩形的x都比它大,即它是最小的,直接把它的x作为它对于答案的贡献,因为它的x比后面矩形的x小,决定了它的y一定比后面所有矩形的y大,想象一下,它的x不会被任何后面的矩形覆盖。

这里能这么做的根本原因其实就在于不存在两个矩形有互相包含的情况。

y方向上与x方向其实是一样的做法。

在查找比某值小的最大值时可以选择二分,二分需要数有序,所以选择集合容器,因为集合在加入元素时默认了升序排序。

这题个人觉得是一道很不错的题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=50005;
int n;
ll ans;
int x[maxn],y[maxn];
void solve()
{
    ans=0;
    set<int>s;
    set<int>::iterator it;
    s.insert(x[n]);
    ans+=x[n];
    for(int i=n-1; i>=1; i--)
    {
        it=s.lower_bound(x[i]);
        if(it==s.begin())
        {
            ans+=x[i];
            s.insert(x[i]);
        }
        else
        {

            it--;
            ans+=x[i]-*it;
            s.insert(x[i]);
        }
    }
    s.clear();
    s.insert(y[n]);
    ans+=y[n];
    for(int i=n-1; i>=1; i--)
    {
        it=s.lower_bound(y[i]);
        if(it==s.begin())
        {
            ans+=y[i];
            s.insert(y[i]);
        }
        else
        {

            it--;
            ans+=y[i]-*it;
            s.insert(y[i]);
        }
    }
    cout<<ans<<endl;
}

int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>x[i]>>y[i];
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zero___zero/article/details/82564125