hdu6638 Snowy Smile

题面 :

题目链接 :

http://acm.hdu.edu.cn/showproblem.php?pid=6638

题目大意 :

给你 N 个点的坐标(X , Y)和权值(W) , 要求你找出一个矩形使得矩形内的点的权值和最大 , 问这个最大权值和为多少

解题思路 :

套路题

一个矩形有上下左右四条边,如果直接枚举四条边,复杂度为 N ^ 4 不可行

如果枚举上下(左右)两条边,再对上下(左右)两边之间的点 dp 求最大连续子段和,复杂度为 N ^ 3 ,还是不可行

如果枚举上下两条边,再对上下两边之间的点建立线段树维护最大连续子段和,操作如下 :

下边每枚举一次重新建立一棵树,上边每枚举一次将边上的点的权值插入线段树中点的横坐标的位置

那么复杂度为 N ^ 2 log N , 可行  ( 因为 X , Y 很大所以要先对 X , Y 离散化一下 )

AC_Code :

#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const int N = 2e3 + 10;
struct Segment_tree
{
    ll l , r;
    ll sum , lmax , rmax , ans;
} tree[N << 2];
void push_up(ll rt)
{
    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
    tree[rt].lmax = max(tree[rt << 1].lmax , tree[rt << 1].sum + tree[rt << 1 | 1].lmax);
    tree[rt].rmax = max(tree[rt << 1 | 1].rmax , tree[rt << 1 | 1].sum + tree[rt << 1].rmax);
    tree[rt].ans = max(tree[rt << 1].rmax + tree[rt << 1 | 1].lmax , max(tree[rt << 1].ans , tree[rt << 1 | 1].ans));
}
void build(ll l , ll r , ll rt , ll *aa)
{
    tree[rt].l = l;
    tree[rt].r = r;
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].sum = aa[l];
        tree[rt].lmax = aa[l];
        tree[rt].rmax = aa[l];
        tree[rt].ans = aa[l];
        return ;
    }
    ll mid = l + r >> 1;
    build(l , mid , rt << 1 , aa);
    build(mid + 1 , r , rt << 1 | 1 , aa);
    push_up(rt);
}
void update(ll pos , ll val , ll rt)
{
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].ans += val;
        tree[rt].sum += val;
        tree[rt].lmax += val;
        tree[rt].rmax += val;
        return ;
    }
    ll mid = tree[rt].l + tree[rt].r >> 1;
    if(pos <= mid)
        update(pos , val , rt << 1);
    if(pos > mid)
        update(pos , val , rt << 1 | 1);
    push_up(rt);
}
Segment_tree query_ans(ll l , ll r , ll rt)
{
    if(l <= tree[rt].l && r >= tree[rt].r)
        return tree[rt];
    ll mid = tree[rt].l + tree[rt].r >> 1;
    if(r <= mid)
        return query_ans(l , r , rt << 1);
    else if(l > mid)
        return query_ans(l , r , rt << 1 | 1);
    else
    {
        Segment_tree Ans , a , b;
        a = query_ans(l , mid , rt << 1);
        b = query_ans(mid + 1 , r , rt << 1 | 1);
        Ans.sum = a.sum + b.sum;
        Ans.lmax = max(a.lmax , a.sum + b.lmax);
        Ans.rmax = max(b.rmax , a.rmax + b.sum);
        Ans.ans = max(a.rmax + b.lmax , max(a.ans , b.ans));
        return Ans;
    }
}
struct node{
    int x , y , w;
    bool operator < (node const & a) const {
        return x < a.x;
    }
}a[N];
vector<node>vec[N];
int n , x[N] , y[N] , aa[N];
signed main()
{
    ios::sync_with_stdio(false);
    int t; 
    cin >> t;
    while(t --)
    {
        cin >> n;
        for(int i = 1 ; i <= n ; i ++)
        {
            cin >> a[i].x >> a[i].y >> a[i].w;
            x[i] = a[i].x , y[i] = a[i].y;
        }
        sort(x + 1 , x + 1 + n) , sort(y + 1 , y + 1 + n);
        int nx = unique(x + 1 , x + 1 + n) - x - 1 , ny = unique(y + 1 , y + 1 + n) - y - 1;
        for(int i = 1 ; i <= n ; i ++)
        {
            a[i].x = lower_bound(x + 1 , x + 1 + nx , a[i].x) - x;
            a[i].y = lower_bound(y + 1 , y + 1 + ny , a[i].y) - y;
            vec[a[i].y].push_back(a[i]);
        }
        int ans = 0;
        for(int i = 1 ; i <= ny ; i ++)
        {
            build(1 , nx , 1 , aa);
            for(int j = i ; j <= ny ; j ++)
            {
                for(auto k : vec[j]) 
                    update(k.x , k.w , 1);
                ans = max(ans , query_ans(1 , n , 1).ans);
            }
        }
        cout << ans << '\n' ;
        for(int i = 1 ; i <= ny ; i ++) vec[i].clear();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/StarRoadTang/p/12915807.html