BZOJ1176: [Balkan2007]Mokia CDQ分治

很裸的一道CDQ分治吧

拆操作 询问区间的时候  拆成询问四个子区间然后加加减减

根据时间顺序来二分 然后用插排降一维  最后一维树状数组维护前缀和


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char c;
inline void read(int &a)
{
	a=0;do c=getchar();while(c<'0'||c>'9');
	while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}

struct O
{
   int x,y,ans,No,op;
   int add;
   inline friend bool operator <(O a,O b)
   {return a.No<b.No||a.No==b.No&&a.op<b.op;}
   inline void print()
   {
   	 printf("  x:%d  y:%d  ans:%d  No:%d op:%d add:%d",x,y,ans,No,op,add);
   	 puts("");
   }
}Line[1000001];

int BIT[5000001];
int base;
inline int low_bit(int a){return a&-a;}
inline void Add(int x,int delta)
{for(int i=x;i<=base;i+=low_bit(i))BIT[i]+=delta;}
inline int Query(int x)
{int res=0;for(int i=x;i;i^=low_bit(i))res+=BIT[i];return res;}

void Solve(int L,int R)
{
	if(L^R)
	 {
	 	int Mid=(L+R)>>1;
	    Solve(L,Mid),Solve(Mid+1,R);
	    int j=L;
	    for(int i=Mid+1;i<=R;i++)
	     if(Line[i].add==0)
		  {
		   while(j<=Mid&&Line[j].x<=Line[i].x)
	       {
	       	 if(Line[j].add)Add(Line[j].y,Line[j].add);
	       	 j++;
	       }
	       Line[i].ans+=Query(Line[i].y); 
		 }
		 j--;
		while(j>=L) 
	    {
	     if(Line[j].add)Add(Line[j].y,-Line[j].add);
	      j--;
		}
	   O A[R-L+2];
	   int x=L,y=Mid+1,con=0;
	   while(x<=Mid&&y<=R) 
	      if(Line[x].x<=Line[y].x)A[++con]=Line[x],x++;
	      else A[++con]=Line[y],y++;

	  while(x<=Mid)
	        A[++con]=Line[x],x++;
	  while(y<=R) 
	        A[++con]=Line[y],y++;	  
	/*  for(int i=1;i<=con;i++)
	     A[i].print();
	  */  for(int i=L;i<=R;i++)
	        Line[i]=A[i-L+1];
//       puts("");puts("");puts("");puts("");
}
	else
	   return;
}
int main()
{
	int S,W;
	read(S),read(W);
    base=W<<1;
	/*for(int i=1;i<=W;i++)	
	    Add(i,S);
	*/
	int n=0,j,jk=0;
    while(true)
     {
     	read(j);
     	if(j==3)break;
        n++;
        if(j==1)
           {
		     read(Line[n].x);
			 read(Line[n].y);
			 read(Line[n].add);
			 Line[n].No=0;      }
	     else
	       {
	       	 ++jk;
	       	 int x1,x2,y1,y2;
	       	 read(x1),read(y1),read(x2),read(y2);
	       	 Line[n]=(O){x1-1,y1-1,0,jk,1,0};
	       	 Line[n].ans+=S*(x2-x1+1)*(y2-y1+1);
			 Line[++n]=(O){x2,y2,0,jk,2,0};
	       	 Line[++n]=(O){x1-1,y2,0,jk,3,0};    
	       	 Line[++n]=(O){x2,y1-1,0,jk,4,0};
	       }
	 }
	 Solve(1,n);
	 sort(Line+1,Line+1+n);
	 int i=1;
	 while(Line[i].No==0)i++;
	 for(;i<=n;i+=4)
	  printf("%d\n",Line[i].ans+Line[i+1].ans-Line[i+2].ans-Line[i+3].ans);
	return 0;
} 


你可能感兴趣的:(bzoj,cdq分治)