2014 UESTC Training for Data Structures D - 长使英雄泪满襟

以下内容来自ShallWe‘s blog

题目

2014 UESTC Training for Data Structures D - 长使英雄泪满襟

看出司马懿在等蜀军粮草不济,孔明于是下令分兵屯田以备久战。司马懿日日只是闭营不出。孔明每日思虑对策至天明,却也无可奈何。漫天星辰中有一类星叫做将星,它们随着将魂的燃烧会越发明亮。今夜五丈原的星空格外璀璨。司马懿一声轻叹。五丈原的星,要落了。

Input

第一行输入三个整数\(n\),\(W\),\(H\),分别表示有\(n\)颗星,矩形宽\(W\),高\(H\)

接下来\(n\)行,每行三个整数,\(x_i\),\(y_i\),\(w_i\)。表示第\(i\)颗星星的在天空的位置是\((x_i,y_i)\),亮度是\(w_i\)
1≤n≤100000,1≤W,H≤1000000,0≤x,y≤100000000,1≤wi≤100

Output

仅一行,该行只包含一个整数,表示平移矩形后,矩形内星星的亮度之和最大能是多少。

解题报告

比较简单的一道扫描线+线段树维护信息的题目。
说说怎么想的,首先,由于矩形的长\(w\),宽\(h\)都是已知的,所以只要固定右下点(当然也可以是别的)那矩形可以控制的stars就是确定的。
比较容易想到的是分别考虑\(x\),\(y\),首先解决\(y\),可以使用扫描线,形象些就是从左向右移动矩形的左边,这样,对于按照\(y\)排序的星星,\(O(n)\)就可以确定哪些在矩形的左右范围内(对于当前左边)。
此时再来处理\(x\),考虑每个星星可以为哪些位置的右下点提供价值,很显然就是一个连续的区间\([x,x+len-1]\)其中,\(len\bf\)是离散化后预处理出来的。所以,当一个星星加入矩形,就是要添加一条线段,使用线段树区间修改全局max来支持操作。

代码

#include <iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
using namespace std;
const int N=10001;
struct node{
    int l,r,mark,mx;
}   seg[N<<2];
int n,W,H;
struct Star{
    int x,y,w,len;
    bool real;
}   star[N<<1];
bool cmpy(const Star &a,const Star &b){
    return a.y==b.y?a.x<b.x:a.y<b.y;
}
bool cmpx(const Star &a,const Star &b){
    return a.x==b.x?a.y<b.y:a.x<b.x;    
}
void build(int x,int l,int r){
    seg[x].l=l;seg[x].r=r;
    if (l==r){
        seg[x].mx=seg[x].mark=0;
        return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
void push_down(int x){
    if (seg[x].mark!=0){
        seg[x*2].mark+=seg[x].mark;
        seg[x*2+1].mark+=seg[x].mark;
        seg[x*2].mx+=seg[x].mark;
        seg[x*2+1].mx+=seg[x].mark;
        seg[x].mark=0;
    }
    return;
}
void add(int l,int r,int x,int val){
    bool b=false;
    if (seg[x].l==seg[x].r){
        seg[x].mx+=val;
        return;
    }
    if (seg[x].l==l&&seg[x].r==r){
        seg[x].mark+=val;
        seg[x].mx+=val;
        return;
    }
    push_down(x);
    int mid=(seg[x].l+seg[x].r)>>1;
    if (l>mid){
        add(l,r,x<<1|1,val);b=true;
    }
    if (r<=mid){
        add(l,r,x<<1,val);b=true;
    }
    if (!b) {
        add(l,mid,x*2,val);
        add(mid+1,r,x*2+1,val);
    }
    seg[x].mx=max(seg[x<<1].mx,seg[x<<1|1].mx);
}

int main(){
    freopen("stars.in","r",stdin);
    freopen("stars.out","w",stdout);
    int g,h,j,l;
    while(cin>>n>>W>>H){
        memset(seg,0,sizeof(seg));
        memset(star,0,sizeof(star));
        for (j=0;j<n;j++) 
            scanf("%d%d%d",&star[j].x,&star[j].y,&star[j].w);
        sort(star,star+n,cmpy);
        h=1;g=0;
        while (g<n){
            while (g<n && star[g].y==star[g+1].y){
                star[g].len=h;
                g++;
            }
            star[g].len=h;
            h++;g++;
        }
        g=0;
        for (j=0;j<n;j++){
            while (g<n&&star[j].y+H>star[g].y) g++;
            g--;
            star[j].y=star[j].len;
            star[j].len=star[g].len-star[j].len+1;
        }
        h=star[n-1].y;
        for (j=0;j<n;j++){
            star[j].real=true;
            star[j+n].x=star[j].x-W;
            star[j+n].y=star[j].y;
            star[j+n].w=star[j].w;
            star[j+n].real=false;
            star[j+n].len=star[j].len;
        }
        sort(star,star+2*n,cmpx);
        build(1,1,h);
        int max=-1;
        for (j=0;j<2*n;j++){
            if (star[j].real) l=-1;else l=1;
            add(star[j].y,star[j].y+star[j].len-1,1,l*star[j].w);
            if (seg[1].mx>max) max=seg[1].mx;
        }
        cout<<max<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/ShallWe2000/p/5762309.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值