zoukankan      html  css  js  c++  java
  • 线段树区间合并+k维空间的曼哈顿距离——cf1093G好题

    和去年多校的CSGO一样,用状态压缩来求Manhattan距离的最大值

    然后要用线段树维护一下区间最大值

    /*
    k维空间给定n个点,两个操作
    1 i b1 b2 .. bk : 修改第i个点的坐标
    2 l r:询问[l,r]区间点最大的曼哈顿距离 
    
    先考虑不带修:
        线段树维护区间2^5种状态的最大值 
        查询时只要求出相对的两个状态的最大值即可
        
    关于这个贪心的证明:
        首先因为绝对值,所以aij前面带的符号可能是-也可能是+,总共就是有关2^k种可能
        那么考虑每种状态 S 的最大值,加上相对这种状态 (1<<k)-S 的最大值,来维护答案 
        其实会有很多情况是不应该存在的,比如aij是第j维最小的,那么其前面的符号就只能是-
        可是当其前面的符号是+时也被考虑进去了,其实能够保证另有一个数比这种情况大
        即这种情况对结果不造成影响        
        
    再来考虑待修的情况
        修改pos位置的点,就要去线段树中更新和这个点有关的2^5种状态
    
    所以还是线段树维护区间最大值的问题,可以用一个结点来维护 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 200005
    int k,n,m,a[maxn][10],v[maxn][1<<5]; 
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    struct Node{int Max,val[1<<5];}p[maxn<<2];
    void pushup(int rt){
        for(int i=0;i<(1<<5);i++)
            p[rt].val[i]=max(p[rt<<1].val[i],p[rt<<1|1].val[i]);
        p[rt].Max=-0x3f3f3f3f;
        for(int i=0;i<(1<<5);i++)
            p[rt].Max=max(p[rt].Max,p[rt].val[i]+p[rt].val[(1<<5)-1-i]);
    }
    void build(int l,int r,int rt){
        if(l==r){
            for(int i=0;i<(1<<5);i++){
                p[rt].val[i]=v[l][i];
    //            p[rt].Max=max(p[rt].Max,v[l][i]);
            }
            return;
        }
        int m=l+r>>1;
        build(lson);build(rson);
        pushup(rt); 
    }
    void update(int pos,int l,int r,int rt){//更新第pos个点 
        if(l==r){
            for(int i=0;i<(1<<5);i++)
                p[rt].val[i]=v[l][i];
            return;
        }
        int m=l+r>>1;
        if(pos<=m)update(pos,lson);
        else update(pos,rson);
        pushup(rt);
    }
    Node merge(Node a,Node b){
        for(int i=0;i<(1<<5);i++)
            a.val[i]=max(a.val[i],b.val[i]);
        for(int i=0;i<(1<<5);i++)
            a.Max=max(a.Max,a.val[i]+b.val[(1<<5)-i-1]);
        return a;
    }
    Node query(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r)
            return p[rt];
        int m=l+r>>1;
        Node res;
        for(int i=0;i<(1<<5);i++)
            res.val[i]=-0x3f3f3f3f;
        res.Max=-0x3f3f3f3f;
            
        if(L<=m)
            res=merge(res,query(L,R,lson));
        if(R>m)    
            res=merge(res,query(L,R,rson));
        return res;
    }
    
    int main(){
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            for(int j=0;j<k;j++)
                scanf("%d",&a[i][j]);
                
            for(int S=0;S<(1<<5);S++){
                for(int j=0;j<5;j++)
                    if(S&(1<<j))v[i][S]+=a[i][j];
                    else v[i][S]-=a[i][j];
            }
        }
        
        build(1,n,1);
        
        cin>>m;
        int op,l,r,pos;
        while(m--){
            scanf("%d",&op);
            if(op==1){
                scanf("%d",&pos);
                for(int i=0;i<k;i++)
                    scanf("%d",&a[pos][i]);
                for(int S=0;S<(1<<5);S++){
                    v[pos][S]=0;
                    for(int j=0;j<5;j++)
                        if(S&(1<<j))
                            v[pos][S]+=a[pos][j];
                        else v[pos][S]-=a[pos][j];
                }
                update(pos,1,n,1);
            }
            else {
                scanf("%d%d",&l,&r);
                Node node=query(l,r,1,n,1);
                cout<<node.Max<<'
    ';
            }
        }
    }
     
  • 相关阅读:
    Can't initialize physical volume "/dev/sdb" of volume group "cinder-volumes" without -ff /dev/sdb: physical volume not initialized.
    openstack核心组件--neutron网络服务2(4)
    openstack部署cinder
    [转载]数字证书原理,公钥私钥加密原理
    [转载]签名、加密、证书的基本原理和理解
    [转载]各种加密算法比较
    [转载]对称加密DES和TripleDES
    [转载]oracle的加密和解密
    PLSQL 问题小记
    [转载]Java中的String,StringBuilder,StringBuffer三者的区别
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10913029.html
Copyright © 2011-2022 走看看