牛客多校第十场 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\n",node[1].maxx);
//    for(int i=1;i<=25;i++){
//        printf("i:%d l:%d r:%d maxx:%d\n",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\n",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\n",node[kk].l,node[kk].r,node[kk].maxx);
//        }
        
        sum+=node[1].maxx;
//        printf("x:%d xkill:%d ykill:%d\n",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\n",ans);
    return 0;
}

 

posted @ 2019-08-17 16:43  Isakovsky  阅读(234)  评论(0编辑  收藏  举报