牛客多校第十场 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; }