zoukankan      html  css  js  c++  java
  • ZOJ 3724 Delivery 树状数组好题

    虽然看起来是求最短路,但因为条件的限制,可以转化为区间求最小值。

    对于一条small path [a, b],假设它的长度是len,它对区间[a, b]的影响就是:len-( sum[b]-sum[a-1] );(使区间[a,b]的原有长度变长或者变短,变长没有意义,所以我们只考虑变短的情况),因为只能选择一条small path,所以对于每个查询[u, v],就是要选择在区间[u, v]内,让原有长度减少最多的那条small path,即求区间最小值。

    离线处理:

    将查询和small path放在一起排序,按u从大到小,v从小到大排。

    因为我们要从后往前扫,对于每个查询[u, v],我们应当保证在本查询之前的所有[u', v']已经更新进去。

    当u < v时,u < u', v' < v,树状数组minv[i]中记录的是以i为区间右端点的所有small path中len-( sum[b]-sum[a-1] )的最小值,答案为[u, v]的区间和+该最小值。

    当u > v时,v' < v, u < u',树状数组minv[i]中记录的是从i点走回i点(走了一个圈)的最小值。答案为最小值减去[u, v]的区间和。

    ------------------------以下吐槽--------------------------

    本来以为不是很难的一道树状数组,结果折腾了一晚上……主要是对查询中u>v的情况处理总是各种出问题,之前我是想把1-N扩大一倍变成1-2N,这样对于查询中u>v的情况就可以转换成查询[ u, N+v ]。事实证明这样转换是不对的……画画图看看就知道为啥了。

    然后我又想关于N轴对称把点翻转过去,还是1-2N,只不过把查询变成了[ u, 2N - v ]。还是各种出错orz……

    最后实在没办法,老老实实的分开处理了……

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    
    #define LL long long int
    
    using namespace std;
    
    const int MAXN = 100000 << 1;
    const int INF = 1000000;
    long long int one = 1;
    
    LL sum[MAXN]; //区间和
    LL minv[MAXN];
    LL ans[200100];
    
    int N, M;
    
    struct node
    {
        int l, r;
        LL val;
        int id;
    };
    
    node D[ MAXN << 1 ];
    
    int lowbit( int x )
    {
        return x & ( -x );
    }
    
    void Add( int x, LL val )
    {
        while ( x <= N )
        {
            minv[x] = min( minv[x], val );
            x += lowbit(x);
        }
        return;
    }
    
    LL Query( int x )
    {
        LL res = one << 60;
        while ( x > 0 )
        {
            res = min( res, minv[x] );
            x -= lowbit(x);
        }
        return res;
    }
    
    bool cmp( node a, node b )
    {
        if ( a.l != b.l ) return a.l > b.l;
        if ( a.r != b.r ) return a.r < b.r;
        return a.id < b.id;
    }
    
    int main()
    {
        //freopen( "in.txt", "r", stdin );
        //freopen( "out.txt", "w", stdout );
        while ( scanf( "%d%d", &N, &M ) == 2 )
        {
            memset( minv, 0, sizeof(minv) );
    
            sum[0] = 0;
            for ( int i = 1; i < N; ++i )
            {
                scanf( "%I64d", &sum[i] );
                sum[i] += sum[i - 1];
            }
            sum[N] = INF;
    
            int cnt = 0;
            for ( int i = 0; i < M; ++i )
            {
                int a, b, c;
                scanf( "%d%d%d", &a, &b, &c );
                LL tmp;
                if ( a > b )
                    tmp = (LL)c + sum[a - 1] - sum[b - 1];
                else
                    tmp = (LL)c - sum[b - 1] + sum[a - 1];
                D[cnt].l = a;
                D[cnt].r = b;
                D[cnt].val = tmp;
                D[cnt].id = -1;
                ++cnt;
            }
    
            int Q;
            scanf( "%d", &Q );
            for ( int i = 0; i < Q; ++i )
            {
                int a, b;
                scanf( "%d%d", &a, &b );
                D[cnt].id = i;
                D[cnt].val = 0;
                D[cnt].l = a;
                D[cnt].r = b;
                ++cnt;
            }
    
            memset( ans, 0, sizeof(ans) );//之前少了这个,一直WA…好像上组数据会影响到下组数据中u=v的情况
            sort( D, D + cnt, cmp );
    
            for ( int i = 0; i < cnt; ++i )
            {
                if ( D[i].l < D[i].r )
                {
                    Add( D[i].r, D[i].val );
                    if ( D[i].id != -1 )
                        ans[ D[i].id ] = sum[ D[i].r - 1 ] - sum[ D[i].l - 1 ] + Query( D[i].r );
                }
            }
    
            for ( int i = 0; i <= N; ++i )
                minv[i] = one << 60;
    
            for ( int i = 0; i < cnt; ++i )
            {
                if ( D[i].l > D[i].r )
                {
                    if ( D[i].id == -1 ) Add( D[i].r, D[i].val );
                    if ( D[i].id != -1 )
                        ans[ D[i].id ] = Query( D[i].r ) - sum[ D[i].l - 1 ] + sum[ D[i].r - 1 ];
                }
            }
    
            for ( int i = 0; i < Q; ++i )
                printf( "%d
    ", (int)ans[i] );
        }
        return 0;
    }
  • 相关阅读:
    videojs播放直播源rtmp时画面在左上角解决方案
    常用git操作命令
    vue使用vue-video-player在直播中的应用
    element-ui隐藏组件scrollbar的使用
    Array.reduce()学习
    阿里云物联网套件(iot)设备间通信(M2M)在web端的实践
    前端axios下载excel(二进制)
    nodejs连接阿里云物联网套件(mqtt)
    base64格式图片转换为FormData对象进行上传
    NodeJS之微信开发
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3269004.html
Copyright © 2011-2022 走看看