• 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 << '
    ' ;
            for(int i = 1 ; i <= ny ; i ++) vec[i].clear();
        }
        return 0;
    }
    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    SDOI2018 旧试题
    JSOI2004 平衡点 / 吊打XXX
    SDOI2017 数字表格
    CQOI2015 选数
    BZOJ2741 【FOTILE模拟赛】L
    BZOJ4103 [Thu Summer Camp 2015]异或运算
    BZOJ3689 异或之
    BZOJ4128 Matrix
    HNOI2006 最短母串问题
    SCOI2013 密码
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/12915807.html
Copyright © 2020-2023  润新知