zoukankan      html  css  js  c++  java
  • 牛客多校第十场 F Popping Balloons 线段树维护稀疏矩阵

    题意:

    给定一个稀疏矩阵,里面有若干个气球,让你横着开三枪,竖着开三枪,问最多能打爆多少气球,要求相同方向,相邻两枪必须间隔r。

    题解:

    横向记录每列有多少个气球,分别在哪行上。

    然后把这个数据改造成以此点为左端点,此列,以及此行右r列,以及右2r列的信息。

    纵向记录每行有多少个气球。

    然后将此数据改造成以此点为下端点,此行,上r行,上2r行的信息。

    将每行有多少个气球用线段树维护。

    枚举竖着开枪的左端点,在线段树上删去那些竖着打爆的气球,然后询问线段树根节点,树上叶节点权值最大为几,就是横着三枪能打爆的最多气球数。

    再把横着打爆的和竖着打爆的加起来维护最大值。

    再把删掉的气球加回来。

    由于矩阵为稀疏矩阵,因此保证在整个横向枚举过程,访问的节点是O(n)的。

    #include<iostream>
    #include<vector> 
    #define MAXN 100005 
    #define LL long long
    using namespace std;
    struct Node{
        int l,r;
    //    int sum;
        int maxx;
    }node[MAXN<<2];
    
    int killy[MAXN];//选择此点为y轴下端点消灭的气球数 
    vector<int> killx[MAXN];//选择此点为x轴左端点能够消灭哪些气球 
    
    void build(int l,int r,int x){
        node[x].l=l;
        node[x].r=r;
        if(l==r){
    //        node[x].sum=killy[l]; 
            node[x].maxx=killy[l];
            return ;
        }else{
            int mid=(l+r)/2;
            build(l,mid,x*2);
            build(mid+1,r,x*2+1);
        }
    //    node[x].sum=node[2*x].sum+node[2*x+1].sum;
        node[x].maxx=max(node[2*x].maxx,node[2*x+1].maxx);
        return ;
    }
    void add(int id,int x,int num){
        if(node[x].l==node[x].r){
    //        node[x].sum+=num;
            node[x].maxx+=num;
            return ;
        }
        if(id<=node[x*2].r){
            add(id,x*2,num);
        }else{
            add(id,x*2+1,num);
        }
    //    node[x].sum=node[2*x].sum+node[2*x+1].sum;
        node[x].maxx=max(node[2*x].maxx,node[2*x+1].maxx);
        return ;
    }
    int main(){
        int n,r;
        int max_x=0,max_y=0;
        scanf("%d %d",&n,&r);
        
        for(int i=1;i<=n;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            x++;
            y++;
            max_x=max(max_x,x);
            max_y=max(max_y,y);
            
            killy[y]++;
            if(y-r>0)killy[y-r]++;
            if(y-r-r>0)killy[y-r-r]++;
            
            killx[x].push_back(y);
            if(x-r>0)killx[x-r].push_back(y);
            if(x-r-r>0)killx[x-r-r].push_back(y); 
        }
        build(1,max_y,1);
        int sum=0,ans=0;
        
    //    printf("%d
    ",node[1].maxx);
    //    for(int i=1;i<=25;i++){
    //        printf("i:%d l:%d r:%d maxx:%d
    ",i,node[i].l,node[i].r,node[i].maxx);
    //    }
        
        for(int i=1;i<=max_x;i++){
            sum=killx[i].size();
            for(int j=0;j<killx[i].size();j++){
    //            printf("%d
    ",killx[i][j]);
                add(killx[i][j],1,-1);
                if(killx[i][j]-r>0)add(killx[i][j]-r,1,-1);
                if(killx[i][j]-r-r>0)add(killx[i][j]-r-r,1,-1);
            }
            
    //        for(int kk=1;kk<=25;kk++){
    //            printf("l:%d r:%d maxx:%d
    ",node[kk].l,node[kk].r,node[kk].maxx);
    //        }
            
            sum+=node[1].maxx;
    //        printf("x:%d xkill:%d ykill:%d
    ",i,killx[i].size(),node[1].maxx);
            ans=max(sum,ans);
            for(int j=0;j<killx[i].size();j++){
                add(killx[i][j],1,1);
                if(killx[i][j]-r>0)add(killx[i][j]-r,1,1);
                if(killx[i][j]-r-r>0)add(killx[i][j]-r-r,1,1);
            }
            
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    升级linux bash
    vim关键字自动补全
    linux bash shell之变量替换::=句法、=句法、:句法、句法、=?句法、?句法、:+句法、+句法
    使用Bash编写Linux Shell脚本7.复合命令
    使用Bash编写Linux Shell脚本5.变量
    使用Bash编写Linux Shell脚本8.调试和版本控制
    Perl之单引号\双引号的字符串直接量
    linux bash shell 中的单引号和双引号
    使用Bash编写Linux Shell脚本6.表达式
    Vim的行号、语法显示等设置,即.vimrc文件的配置
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11369226.html
Copyright © 2011-2022 走看看