bzoj 1176 Mokia(CDQ分治)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1176 Mokia(CDQ分治)相关的知识,希望对你有一定的参考价值。

  

【题目链接】

 

  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=96974

 

【题意】

 

    定义查询操作与修改操作:1 x y z 为将格子(x,y)修改为z;2 x1 y1 x2 y2为查询以(x1,y1)为左上(x2,y2)为右下的子矩阵之和。

 

【思路】

 

    cdq分治。

    矩阵初始值都为s,所以先不考虑。

    首先明确每一个修改操作都互不影响。然后把每一个对子矩阵的询问操作差分为对四个点的“前缀和”操作。

    先把所有的操作按照x升序排列。进行cdq分治。

    定义solve(l,r)为解决查询顺序在l,r区间内的操作,且在solve结束后保证区间按照x的递增排列。

  1) 将区间按照查询先后顺序重排

  2) Solve(l,mid)

  3) 计算左区间对右区间的贡献。这时候左区间是按照x升序排列的,右区间是按照查询先后排列的,这样正好既可以保证求贡献时左区间x的单调与递归右区间时右区间内所有的查询都在。对于右区间的i,将左区间内x所有小于它的加入BIT,维护区间和,如果i是询问则查询BIT中所有y小于它的z之和。

  4) Solve(mid+1,r)

  5) 恢复区间,按照x升序排列

    最后答案加上矩阵的s即可。

  BIT的清理也可通过加时间戳的方式做到。

 

【代码】

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int N = 2*1e6+10;
  8 const int inf = 1e9+7;
  9 
 10 int n,sz,s,w;
 11 int C[N],flag[N],T,tmp[N];
 12 
 13 struct Node {
 14     int x,y,z,pos,ans;
 15     bool operator<(const Node& rhs) const{
 16         return x<rhs.x;
 17     }
 18     Node(int x=0,int y=0,int z=0) {
 19         this->x=x,this->y=y,this->z=z;
 20         pos=sz; ans=0;
 21     }
 22 }q[N],t[N];
 23 bool cmp(const Node& x,const Node& y)
 24 {
 25     return x.pos<y.pos;
 26 }
 27 
 28 void add(int x,int v)
 29 {
 30     for(;x<=w;x+=x&-x)
 31         if(flag[x]!=T) flag[x]=T,C[x]=v;
 32         else C[x]+=v;
 33 }
 34 int query(int x)
 35 {
 36     int res=0;
 37     for(;x;x-=x&-x)
 38         if(flag[x]==T) res+=C[x];
 39     return res;
 40 }
 41 
 42 void solve(int l,int r)
 43 {
 44     if(l==r) return ;
 45     int mid=(l+r)>>1;
 46     int l1=l,l2=mid+1,i,j;
 47     for(i=l;i<=r;i++) {
 48         if(q[i].pos<=mid) t[l1++]=q[i];
 49         else t[l2++]=q[i];
 50     }
 51     memcpy(q+l,t+l,sizeof(q[0])*(r-l+1));
 52     solve(l,mid);
 53     j=l; T++;
 54     for(i=mid+1;i<=r;i++) {
 55         for(;j<=mid&&q[j].x<=q[i].x;j++)
 56             if(q[j].z!=-inf) add(q[j].y,q[j].z);
 57         if(q[i].z==-inf) q[i].ans+=query(q[i].y);
 58     }
 59     solve(mid+1,r);
 60     l1=l,l2=mid+1; int now=l;
 61     while(l1<=mid||l2<=r) {
 62         if(l2>r||l1<=mid&&q[l1]<q[l2]) t[now++]=q[l1++];
 63         else t[now++]=q[l2++];
 64     }
 65     memcpy(q+l,t+l,sizeof(q[0])*(r-l+1));
 66 }
 67 
 68 void read(int &x)
 69 {
 70     char c=getchar(); x=0;int f=1;
 71     while(!isdigit(c)){ if(c==-)f=-1; c=getchar(); }
 72     while(isdigit(c)) x=x*10+c-0 , c=getchar();
 73     x*=f;
 74 }
 75 
 76 int main()
 77 {
 78     read(s),read(w);
 79     int op,x1,y1,x2,y2,z;
 80     while(read(op),op!=3)
 81     {
 82         if(op==1) {
 83             read(x1),read(y1),read(z);
 84             q[++sz]=(Node){x1,y1,z};
 85         } else {
 86             read(x1),read(y1),read(x2),read(y2);
 87             q[++sz]=Node(x1-1,y1-1,-inf);
 88             tmp[sz]=abs(x1-x2+1)*abs(y1-y2+1)*s;
 89             q[++sz]=Node(x1-1,y2,-inf);
 90             q[++sz]=Node(x2,y1-1,-inf);
 91             q[++sz]=Node(x2,y2,-inf);
 92         }
 93     }
 94     sort(q+1,q+sz+1);
 95     solve(1,sz);
 96     sort(q+1,q+sz+1,cmp);
 97     for(int i=1;i<=sz;i++) if(q[i].z==-inf) {
 98         int ans=tmp[i];
 99         ans+=q[i++].ans;
100         ans-=q[i++].ans;
101         ans-=q[i++].ans;
102         ans+=q[i++].ans;
103         i--;
104         printf("%d\n",ans);
105     }
106     return 0;
107 }

  ps:鄙人并非权限汪,如代码不能AC概不负责 :)

 

以上是关于bzoj 1176 Mokia(CDQ分治)的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj] 1176 Mokia || CDQ分治

[BZOJ 1176&COGS 1752][BOI2007]Mokia(CDQ分治)

BZOJ-1176&2683Mokia&简单题 CDQ分治

cdq分治入门--BZOJ1176: [Balkan2007]Mokia

bzoj 1176 [Balkan2007]Mokia - CDQ分治 - 树状数组

BZOJ 1176 MOKIA