题解 P4390 【[BOI2007]Mokia 摩基亚】

这道题我爱了!

思路

看到这题目我直接想到了三值偏序,然后我就开始了不归之路

1.把操作按时间排序,就能离线操作了

2.首先读入的时候各个操作已经默认是按时间排序的了,所以不用考虑时间这一维

接着,操作分两种:
(1).添加住户(相当于是把这个点的权值加上一个a)

(2).查询住户(查询的这个范围是个矩形)

所以自然就可以用归并排序+树状数组来解决了

其中最妙的一步在于将操作2中的给出的两个点进行扩展,扩展成4个点来进行操作,然后在归并排序的时候按照坐标x来排序,根据树状数组的性质来进行操作:

结合代码来讲一下

for (;tql!=3;){
    cin>>tql;
    if(tql == 1)R++,T[R].tt=R,cin>>T[R].x>>T[R].y>>T[R].z;
    if(tql == 2){
        R++;
        int m=R;
        book[m]=1;
        R=R,T[R].t=1,cin>>T[R].x>>T[R].y,T[R].tt=m;
        T[R].x--,T[R].y--;
        R++,T[R].t=4,cin>>T[R].x>>T[R].y,T[R].tt=m;
        R++,T[R].t=2,T[R].x=T[R-2].x,T[R].y=T[R-1].y,T[R].tt=m;
        R++,T[R].t=3,T[R].x=T[R-2].x,T[R].y=T[R-3].y,T[R].tt=m;
    }

}

(见tql==2的情况)

(给拓展的四个点进行标记然后在后面计算答案)

if(T[t2].t == 1)tong[T[t2].tt]+=get(T[t2].y);

if(T[t2].t == 2)tong[T[t2].tt]-=get(T[t2].y);

if(T[t2].t == 3)tong[T[t2].tt]-=get(T[t2].y);if(T[

t2].t == 4)tong[T[t2].tt]+=get(T[t2].y);

此处请自行脑补一个树状数组

借用前面题解的图片来理解

CODE

#include  <bits/stdc++.h>
using namespace std;
int c[2005001];
int tong[200001];
int w,tql,R=0;
struct node{int x,y,z,t,tt;}T[200001],p[200001];
int book[200005];
int lowbit(int x){return x&(-x);}

int add(int x,int k){
  while(x <= w)c[x]+=k,x+=lowbit(x);
  return 0;
}

int get(int x){
  int total=0;
  while(x > 0)
  total+=c[x],x-=lowbit(x);
  return total;
}

int CDQ(int l , int r ){
  if(l == r)return 0;
  int mid=(l+r)>>1;
  CDQ(l,mid);CDQ(mid+1,r);
  int t1=l,t2=mid+1;
  for (int i = l ; i <= r ; i ++){
      if(T[t1].x <= T[t2].x && t1 <=mid || t2 > r){
          if(T[t1].t == 0)add(T[t1].y,T[t1].z);
          p[i]=T[t1],t1++;
      }
      else {
          if(T[t2].t == 1)tong[T[t2].tt]+=get(T[t2].y);
          if(T[t2].t == 2)tong[T[t2].tt]-=get(T[t2].y);
          if(T[t2].t == 3)tong[T[t2].tt]-=get(T[t2].y);
          if(T[t2].t == 4)tong[T[t2].tt]+=get(T[t2].y);
          p[i]=T[t2],t2++;
      }
  }
  for (int i = l ; i <= mid ; i ++)
  if(T[i].t == 0)add(T[i].y,-T[i].z);
  for (int i = l ; i <= r ; i ++)
  T[i]=p[i];
  return 0;
}
int main(){
  cin>>tql>>w;
  R=0;
  for (;tql!=3;){
      cin>>tql;
      if(tql == 1)R++,T[R].tt=R,cin>>T[R].x>>T[R].y>>T[R].z;
      if(tql == 2){
          R++;
          int m=R;
          book[m]=1;
          R=R,T[R].t=1,cin>>T[R].x>>T[R].y,T[R].tt=m;
          T[R].x--,T[R].y--;
          R++,T[R].t=4,cin>>T[R].x>>T[R].y,T[R].tt=m;
          R++,T[R].t=2,T[R].x=T[R-2].x,T[R].y=T[R-1].y,T[R].tt=m;
          R++,T[R].t=3,T[R].x=T[R-2].x,T[R].y=T[R-3].y,T[R].tt=m;
      }
      if(tql == 3)break;
  }
  
  CDQ(1,R);
  for (int i = 1 ; i <= R ; i ++)
  if(book[i] != 0)cout<<tong[i]<<endl;
  return 0;
}
posted @ 2020-10-24 16:34  MYCui  阅读(104)  评论(0编辑  收藏  举报