COGS1752 [BOI2007]摩基亚Mokia(CDQ分治 + 二维前缀和 + 线段树)

题目这么说的:

摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统。和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米。但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题。

在定位系统中,世界被认为是一个W×W的正方形区域,由1×1的方格组成。每个方格都有一个坐标(x,y)1<=x,y<=W。坐标的编号从1开始。对于一个4×4的正方形,就有1<=x<=4,1<=y<=4(如图):

请帮助Mokia公司编写一个程序来计算在某个矩形区域内有多少名用户。

有三种命令,意义如下:

0 W 初始化一个全零矩阵。本命令仅开始时出现一次。
1 x y A 向方格(x,y)中添加A个用户。A是正整数。
2 X1 Y1 X2 Y2 查询X1<=x<=X2,Y1<=y<=Y2所规定的矩形中的用户数量
3 无参数 结束程序。本命令仅结束时出现一次。

 

这篇题解写得挺详细的:http://wulala.logdown.com/posts/207262-boi-2007-mokia。

。。然后感觉这题转化成二维前缀和的差分挺厉害的。

  1 #include
  2 #include
  3 #include
  4 using namespace std;
  5 
  6 long long tree[2000000<<2];
  7 int N,x,y;
  8 void update(int i,int j,int k){
  9     if(i==j){
 10         tree[k]+=y;
 11         return;
 12     }
 13     int mid=i+j>>1;
 14     if(x<=mid) update(i,mid,k<<1);
 15     else update(mid+1,j,k<<1|1);
 16     tree[k]=tree[k<<1]+tree[k<<1|1];
 17 }
 18 long long query(int i,int j,int k){
 19     if(x>y) return 0;
 20     if(x<=i && j<=y){
 21         return tree[k];
 22     }
 23     int mid=i+j>>1;
 24     long long res=0;
 25     if(x<=mid) res+=query(i,mid,k<<1);
 26     if(y>mid) res+=query(mid+1,j,k<<1|1);
 27     return res;
 28 }
 29 
 30 struct Query{
 31     int idx,type,anspos;
 32     int x,y,A;
 33     bool operator<(const Query &q) const {
 34         return x<q.x;
 35     }
 36 }que[222222],tmp[222222];
 37 
 38 long long ans[11111];
 39 
 40 void cdq(int l,int r){
 41     if(l>=r) return;
 42     int mid=l+r>>1,i=l,j=mid+1;
 43     for(int k=l; k<=r; ++k){
 44         if(que[k].idx<=mid) tmp[i++]=que[k];
 45         else tmp[j++]=que[k];
 46     }
 47     for(int k=l; k<=r; ++k){
 48         que[k]=tmp[k];
 49     }
 50 
 51     for(i=mid+1,j=l; i<=r; ++i){
 52         if(que[i].type==1) continue;
 53         for( ; j<=mid && que[j].x<=que[i].x; ++j){
 54             if(que[j].type==2) continue;
 55             x=que[j].y; y=que[j].A;
 56             update(1,N,1);
 57         }
 58         x=1; y=que[i].y;
 59         ans[que[i].anspos]+=query(1,N,1)*que[i].A;
 60     }
 61 
 62     for(int i=l; ii){
 63         if(que[i].type==2) continue;
 64         x=que[i].y; y=-que[i].A;
 65         update(1,N,1);
 66     }
 67 
 68     cdq(l,mid); cdq(mid+1,r);
 69 }
 70 
 71 int main(){
 72     //freopen("mokia.in","r",stdin); freopen("mokia.out","w",stdout);
 73 
 74     int op,n,a,b,c,d;
 75     scanf("%d%d",&op,&n);
 76     int opn=0,cnt=0;
 77     while(scanf("%d",&op),op!=3){
 78         if(op==1){
 79             scanf("%d%d%d",&a,&b,&c);
 80             que[++opn].idx=opn; que[opn].type=1; que[opn].x=a; que[opn].y=b; que[opn].A=c;
 81         }else if(op==2){
 82             scanf("%d%d%d%d",&a,&b,&c,&d);
 83             ++cnt;
 84             que[++opn].idx=opn; que[opn].type=2; que[opn].anspos=cnt; que[opn].x=c; que[opn].y=d; que[opn].A=1;
 85             que[++opn].idx=opn; que[opn].type=2; que[opn].anspos=cnt; que[opn].x=c; que[opn].y=b-1; que[opn].A=-1;
 86             que[++opn].idx=opn; que[opn].type=2; que[opn].anspos=cnt; que[opn].x=a-1; que[opn].y=d; que[opn].A=-1;
 87             que[++opn].idx=opn; que[opn].type=2; que[opn].anspos=cnt; que[opn].x=a-1; que[opn].y=b-1; que[opn].A=1;
 88         }
 89     }
 90 
 91     for(N=1; N1);
 92 
 93     sort(que+1,que+1+opn);
 94     cdq(1,opn);
 95 
 96     for(int i=1; i<=cnt; ++i){
 97         printf("%lld\n",ans[i]);
 98     }
 99     return 0;
100 }

转载于:https://www.cnblogs.com/WABoss/p/5705466.html

你可能感兴趣的:(COGS1752 [BOI2007]摩基亚Mokia(CDQ分治 + 二维前缀和 + 线段树))