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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章