Educational Codeforces Round 73 (Rated for Div. 2)F. Choose a Square(扫描线+线段树)

F. Choose a Square

题意:

输入 n ( 1 ≤ n ≤ 5 e 5 ) n(1\leq n\leq5e5) n(1n5e5),表示有 n n n个点,接下来 n n n行,每行 x i , y i , c i ( 0 ≤ x i , y i ≤ 1 0 9 , − 1 0 6 ≤ c i ≤ 1 0 6 ) x_i,y_i,c_i(0\leq x_i,y_i\leq10^9,-10^6\leq c_i\leq10^6) xi,yi,ci(0xi,yi109,106ci106)。要求选取一个对角线再 y = x y=x y=x上的一个正方形,使得正方形围成的 ( ∑ c i ) − l ( 正 方 形 边 长 ) (\sum c_i)-l(正方形边长) (ci)l()最大。

题解:

首先分析对于一个点 ( x , y ) (x,y) (x,y)来说如何使他被正方形(左下角 ( l , l ) (l,l) (l,l),右上角 ( r , r ) (r,r) (r,r))包含,其实只要满足 l ≤ m i n ( x , y ) ≤ m a x ( x , y ) ≤ r l \leq min(x,y)\leq max(x,y)\leq r lmin(x,y)max(x,y)r,那么不妨使所有的点 x ≤ y x\leq y xy,这样只要使 l ≤ x ≤ y ≤ r l\leq x\leq y \leq r lxyr
然后把 x , y , c x,y,c x,y,c x x x从小到大排序,接下来扫一遍 x x x,查询更新线段树就好。
线段树维护的是 p a i r pair pair(最大值,最大值所对应的下标);初始化线段树,一开始先把所有的 − r -r r加入线段树,对于 x x x更新 y − m a x n y-maxn ymaxn c c c,这样维护的就是 m a x ( ( ∑ c ) − r ) max((\sum c)-r) max((c)r),再把固定的 l l l加上就是固定 l l l时最大的答案。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

代码:

#include<bits/stdc++.h>
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define ll long long
#define P pair<ll,ll>
using namespace std;
const int N=5e5+9;
int n;
struct T{int x,y,c;}a[N];
int x[N],nx;
ll ans,z,y;
bool cmp(T t1,T t2){return t1.x<t2.x;}
inline int getid(int y){return lower_bound(x+1,x+nx+1,y)-x;}
ll add[N<<2];
P mx[N<<2];
void push_down(int p){
    if(add[p]){
        add[ls(p)]+=add[p],add[rs(p)]+=add[p];
        mx[ls(p)].first+=add[p],mx[rs(p)].first+=add[p];
        add[p]=0;
    }
}
void push_up(int p){mx[p]=max(mx[ls(p)],mx[rs(p)]);}
void update(int p,int l,int r,int ql,int qr,int qz){
    if(ql<=l&&r<=qr){mx[p].first+=qz,add[p]+=qz;if(l==r)mx[p].second=l;}
    else{
        push_down(p);
        int mid=(l+r)>>1;
        if(ql<=mid)update(ls(p),l,mid,ql,qr,qz);
        if(qr>mid)update(rs(p),mid+1,r,ql,qr,qz);
        push_up(p);
     //   cout<<"yu"<<p<<" "<<mx[p].first<<" "<<mx[p].second<<endl;
    }
}
P query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return mx[p];
    else{
        push_down(p);
        int mid=(l+r)>>1;
        P ans=P(-2e9,0);
        if(ql<=mid)ans=query(ls(p),l,mid,ql,qr);
        if(qr>mid)ans=max(ans,query(rs(p),mid+1,r,ql,qr));
     //   cout<<"tu"<<p<<" "<<ans.first<<" "<<ans.second<<endl;
        return ans;
    }
}
/*void query(int p,int l,int r,int qx){
    if(l==r)cout<<"pu"<<l<<" "<<p<<" "<<mx[p].first<<" "<<mx[p].second<<endl;
    else{
        push_down(p);
        int mid=(l+r)>>1;
        query(ls(p),l,mid,qx);
        query(rs(p),mid+1,r,qx);
        cout<<"pu"<<p<<" "<<mx[p].first<<" "<<mx[p].second<<endl;
    }
}*/
int main(){
   // freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y>>a[i].c;
        if(a[i].x>a[i].y)swap(a[i].x,a[i].y);
        x[++nx]=a[i].y;
    }
    sort(a+1,a+n+1,cmp);
   // for(int i=1;i<=n;i++)cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].c<<endl;
    sort(x+1,x+nx+1),nx=unique(x+1,x+nx+1)-x-1;
    for(int i=1;i<=nx;i++)update(1,1,nx,i,i,-x[i]);
    for(int i=1;i<=n;i++)update(1,1,nx,getid(a[i].y),nx,a[i].c);
    //query(1,1,nx,1);
   // for(int i=1;i<=nx;i++)cout<<query(1,1,nx,i).first<<" "<<query(1,1,nx,i).second<<endl;
    z=y=2e9;
    for(int i=1;i<=n;i++){
       // query(1,1,nx,1);
        P zd=query(1,1,nx,getid(a[i].x),nx);
    //    cout<<"---"<<zd.first<<" "<<zd.second<<endl;
    //    cout<<a[i].x<<endl;
        if(ans<zd.first+a[i].x)ans=zd.first+a[i].x,z=a[i].x,y=x[zd.second];
        update(1,1,nx,getid(a[i].y),nx,-a[i].c);//cout<<a[i].y<<" "<<nx<<" "<<-a[i].c<<endl;
        while(i+1<=n&&a[i+1].x==a[i].x)i++,update(1,1,nx,getid(a[i].y),nx,-a[i].c);//cout<<a[i].y<<" "<<nx<<" "<<-a[i].c<<endl;
    }
    cout<<ans<<endl;
    cout<<z<<" "<<z<<" "<<y<<" "<<y<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值