Codeforces Round 73F. Choose a Square 线段树

题目链接: https://codeforces.com/contest/1221/problem/F

题意:

二维平面上有 nn 个带权值的点,选择一个 [(a,a),(b,b)](a<=b)[(a,a),(b,b)] (a<=b) 的一个正方形区域获得的权值是该区域内点权的和减去正方形边长。 现在要你选择一个值最大的区域,输出最大权值 vv 和选择的范围 aabb

做法:

这种枚举做法其实已经碰到好多次了,之前网络赛也有一场类似的从后向前枚举,然后不断更新值的做法。

先跟着比较专业的大佬题解的做法说,因为如果我们要选择一个点 ii ,那么一定是我们选择的区间 [l,r][l,r] 满足 l<=min(x[i],y[i]),r>=max(x[i],y[i])l<=min(x[i],y[i]),r>=max(x[i],y[i]) 这样的条件的,所以我们完全可以把这个二维空间转化为一维来做。

x[i]x[i]y[i]y[i] 中的较小值先记录下来(如 x=2,y=5x=2,y=5,那么这个点我们就在枚举到 22 的时候再做),从大到小去枚举要做的这个值,拿到这个点之后,我们就要在区间 [max(x[i],y[i]),num][max(x[i],y[i]),num] 上去更新这个点,因为我们这个较小的值被枚举到后,这个点的左区间就已经被包括了,所以从这个点的右区间开始都要更新。

至于减去边长的问题我们可以在一开始的时候就先build好,在枚举值的时候,这个值之前的长度被加上,就可以把边长问题解决掉了。

代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
using namespace std;
const int maxn=500005;
const int maxm=1000055;
typedef long long ll;
int n,x[maxn],y[maxn],tmp[maxm],ct,mxd[maxm<<2];
ll ansl,ansr,ans,mx[maxm<<2],laz[maxm<<2],tans,tid,v[maxn];
vector<int> id[maxm];
void push_up(int rt){
    if(mx[lson]>=mx[rson]) mx[rt]=mx[lson],mxd[rt]=mxd[lson];
    else mx[rt]=mx[rson],mxd[rt]=mxd[rson];
}
void build(int l,int r,int rt){
    if(l==r){
        mx[rt]=-tmp[l];
        mxd[rt]=l;
        return ;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    push_up(rt);
}
void deal(int rt,ll v){
    laz[rt]+=v; mx[rt]+=v;
}
 
void push_down(int rt){
    if(laz[rt]){
        deal(lson,laz[rt]);
        deal(rson,laz[rt]);
        laz[rt]=0;
    }
}
void update(int l,int r,int rt,int ql,int qr,ll v){
    if(ql<=l&&r<=qr){
        deal(rt,v);
        return ;
    }
    push_down(rt);
    if(mid>=ql) update(l,mid,lson,ql,qr,v);
    if(mid<qr) update(mid+1,r,rson,ql,qr,v);
    push_up(rt);
}
 
void query(int l,int r,int rt,int ql,int qr){
    if(ql<=l&&r<=qr){
        if(mx[rt]>tans) tans=mx[rt],tid=mxd[rt];
        return ;
    }
    push_down(rt);
    if(mid>=ql) query(l,mid,lson,ql,qr);
    if(mid<qr) query(mid+1,r,rson,ql,qr);
}
int main(){
    scanf("%d",&n);
    rep(i,1,n){
        scanf("%d%d%lld",&x[i],&y[i],&v[i]);
        if(x[i]>y[i]) swap(x[i],y[i]);
        tmp[++ct]=x[i],tmp[++ct]=y[i];
    }
    sort(tmp+1,tmp+1+ct);
    ct=unique(tmp+1,tmp+1+ct)-tmp-1;
    rep(i,1,n){
        x[i]=lower_bound(tmp+1,tmp+1+ct,x[i])-tmp;
        y[i]=lower_bound(tmp+1,tmp+1+ct,y[i])-tmp;
        id[x[i]].push_back(i);
    }
    build(1,ct,1);
    ans=0; ansl=tmp[ct]+1,ansr=tmp[ct]+1;
    for(int i=ct;i>=1;i--){
        for(auto u:id[i]){
            update(1,ct,1,y[u],ct,v[u]);
        }
        tans=-1e9;
        query(1,ct,1,i,ct);
        if(ans<tans+tmp[i]){
            ans=tans+tmp[i];
            ansl=tmp[i],ansr=tmp[tid];
        }
    }
    printf("%lld\n%lld %lld %lld %lld\n",ans,ansl,ansl,ansr,ansr);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章