无法拯救我的菜----徐州网络赛 G. Trace

地址:https://nanti.jisuanke.com/t/31459

线段树做法:讨论其中的宽度:
如果时间正好是升序,高度正好是降序排序,那么每一次都把宽度累加就是最后的答案,我们可以先把高度按照降序排序。排序后不能保证时间是升序的,那么时间大的可以覆盖掉时间小的。但是在高度是降序的排序的情况下只能是排序后在前面的并且时间还大于当前的波浪的时间,当前波浪才会被覆盖掉。
鉴于这点我们需要知道比当前波浪高度高的并且时间大于当前波浪的最长的宽度,所以我们建一个以时间为下标的线段树

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 50005;

int tree[4 * N];
typedef struct Node{
    int w,h,id;
}Node;
Node node[N];

bool cmp1(const Node &p,const Node &q)
{
    return p.w > q.w;
}

bool cmp2(const Node &p,const Node &q)
{
    return p.h > q.h;
}

void update(int root,int l,int r,int index,int val)
{
    if(l == r)
    {
        if(l == index){
            tree[root] = val;
        }
        return ;
    }
    int mid = (l + r) / 2;
    if(index <= mid){
        update(root * 2 + 1,l,mid,index,val);
    }else{
        update(root * 2 + 2,mid + 1,r,index,val);
    }
    tree[root] = max(tree[root * 2 + 1],tree[root * 2 + 2]);
}

int query(int root,int l,int r,int ql,int qr)
{
    if(ql > r || qr < l){
        return 0;
    }
    if(ql <= l && r <= qr){
        return tree[root];
    }
    int mid = (l + r) / 2;
    return max(query(root * 2 + 1,l,mid,ql,qr),query(root * 2 + 2,mid + 1,r,ql,qr));
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;++i)
    {
        scanf("%d %d",&node[i].w,&node[i].h);
        node[i].id = i;
    }
    memset(tree,0,sizeof(tree));
    sort(node + 1,node + 1 + n,cmp1);
    LL res = 0;
    for(int i = 1;i <= n;++i)
    {
        int num = query(1,1,n,node[i].id,n);
        if(node[i].h > num){
            res += (node[i].h - num);
        }
        update(1,1,n,node[i].id,node[i].h);
    }
    memset(tree,0,sizeof(tree));
    sort(node + 1,node + n + 1,cmp2);
    for(int i = 1;i <= n;++i)
    {
        int num = query(1,1,n,node[i].id,n);
        if(node[i].w > num){
            res += (node[i].w - num);
        }
        update(1,1,n,node[i].id,node[i].w);
    }
    printf("%lld\n",res);
    return 0;
}

set做法:单独考虑高度和宽度,例如高度,倒着遍历,处理过的高度入set,set里的值都是时间值大的,如何set里存在值比当前值小,那么一定会出现覆盖,找到比当前值小的值里面的最大值,宽度类似

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;

vector<int>x;
vector<int>y;
set<int>se;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 0;i < n;++i)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        x.push_back(a);
        y.push_back(b);
    }
    LL sum = 0;
    for(int i = n - 1;i >= 0;--i)
    {
        set<int>::iterator it = se.lower_bound(x[i]);
        if(it == se.begin()){
            sum += x[i];
        }else{
            it--;
            sum += (x[i] - *it);
        }
        se.insert(x[i]);
    }
    se.clear();
    for(int i = n - 1;i >= 0;--i)
    {
        set<int>::iterator it = se.lower_bound(y[i]);
        if(it == se.begin()){
            sum += y[i];
        }else{
            it--;
            sum += (y[i] - *it);
        }
        se.insert(y[i]);
    }
    printf("%lld\n",sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/82596541