• 【bzoj 2716】[Violet 3]天使玩偶 (CDQ+树状数组)


    题目描述

    Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。

    我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远。

    因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|Ax-Bx|+|Ay-By|。其中 Ax 表示点 A的横坐标,其余类似。

    输入输出格式

    输入格式:

    第一行包含两个整数n和m ,在刚开始时,Ayu 已经知道有n个点可能埋着天使玩偶, 接下来 Ayu 要进行m 次操作

    接下来n行,每行两个非负整数 (xi,yi),表示初始n个点的坐标。

    再接下来m 行,每行三个非负整数 t,xi,yi。

    如果t=1 ,则表示 Ayu 又回忆起了一个可能埋着玩偶的点 (xi,yi) 。

    如果t=2 ,则表示 Ayu 询问如果她在点 (xi,yi) ,那么在已经回忆出来的点里,离她近的那个点有多远

    输出格式:

    对于每个t=2 的询问,在单独的一行内输出该询问的结果。

    输入输出样例

    输入样例#1: 复制
    2 3 
    1 1 
    2 3 
    2 1 2 
    1 3 3 
    2 4 2
    输出样例#1: 复制
    1 
    2

    说明

    n,m<=300 000

    xi,yi<=1 000 000

    题解

    先膜一发大佬

    据说这题正解KD-tree,然而我只会CDQ……还想了半天啥都没想出来……

    先假设,所有回忆出来的点都在查询点的左下方,那么距离如下(A为查询点,B为某一个回忆出来的点)

    $$Dist(A,B)=|x_A-x_B|+|y_A-y_B|=(x_A+y_A)-(x_B+y_B)$$

    因为$x_A+y_A$对同一个查询点来说是一个定值,所以只要找到$x_B+y_B$的最大值,就可以找到$Dist(A,B)$的最小值

    于是问题就转化为:对于一个询问$(x,y)$,查找$x_i<=x,y_i<=y$且$i$的时间戳小于当前询问的最大$x_i+y_i$,很明显,这就是一个三维偏序问题,可以用CDQ求解

    然而问题是不能保证所有点都在查询点的下方,所以我们要将其他四个方位的点的坐标变换一下。简单来说就是旋转整张图,然后在四个答案里取最小的就好了

    所以做四遍CDQ(当初刚看到这句话差点没吓到……)

    然后有几个向大佬学习的优化

    1.每次CDQ前,把肯定不在左下方的点去掉

    2.每一次重新建图很麻烦,直接保留一个原图然后转一下就好了

    感觉我对CDQ理解还是太浅了……

      1 //minamoto
      2 #include<cstdio>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cstring>
      6 using namespace std;
      7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      8 char buf[1<<21],*p1=buf,*p2=buf;
      9 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
     10 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
     11 inline int read(){
     12     #define num ch-'0'
     13     char ch;bool flag=0;int res;
     14     while(!isdigit(ch=getc()))
     15     (ch=='-')&&(flag=true);
     16     for(res=num;isdigit(ch=getc());res=res*10+num);
     17     (flag)&&(res=-res);
     18     #undef num
     19     return res;
     20 }
     21 char sr[1<<21],z[20];int C=-1,Z;
     22 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
     23 inline void print(int x){
     24     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
     25     while(z[++Z]=x%10+48,x/=10);
     26     while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
     27 }
     28 const int N=1e6+5,inf=0x3f3f3f3f;
     29 int n,m,lx,ly,rx,ry,c[N],ans[N];
     30 inline void clear(int x){
     31     for(int i=x;i<=ly;i+=i&-i)
     32     if(c[i]) c[i]=0;else break;
     33 }
     34 inline void add(int x,int val){
     35     for(int i=x;i<=ly;i+=i&-i)
     36     cmax(c[i],val);
     37 }
     38 inline int query(int x){
     39     int res=0;
     40     for(int i=x;i;i-=i&-i)
     41     cmax(res,c[i]);
     42     return res;
     43 }
     44 struct node{
     45     int x,y,t;bool f;
     46     node(){}
     47     node(const int &x,const int &y,const int &t,const int &f):
     48         x(x),y(y),t(t),f(f){}
     49     inline bool operator <(const node &b)const
     50     {return x<b.x||(x==b.x&&y<b.y);}
     51 }a[N],p[N],q[N];
     52 void CDQ(int l,int r){
     53     if(l==r) return;
     54     int mid=(l+r)>>1;
     55     CDQ(l,mid),CDQ(mid+1,r);
     56     int j=l;
     57     for(int i=mid+1;i<=r;++i)
     58     if(!p[i].f){
     59         while(j<=mid&&p[j].x<=p[i].x){if(p[j].f) add(p[j].y,p[j].x+p[j].y);++j;}
     60         int tmp=query(p[i].y);
     61         if(tmp) tmp=p[i].x+p[i].y-tmp,cmin(ans[p[i].t],tmp);
     62     }
     63     for(int i=l;i<j;++i)
     64     if(p[i].f) clear(p[i].y);
     65     merge(p+l,p+mid+1,p+mid+1,p+r+1,q+l);
     66     memcpy(p+l,q+l,sizeof(node)*(r-l+1));
     67 }
     68 void check(){
     69     rx=ry=m=0;
     70     for(int i=1;i<=n;++i)
     71     if(!p[i].f) cmax(rx,p[i].x),cmax(ry,p[i].y);
     72     for(int i=1;i<=n;++i)
     73     if(p[i].x<=rx&&p[i].y<=ry) q[++m]=p[i];
     74     memcpy(p+1,q+1,sizeof(node)*m);
     75 }
     76 int main(){
     77     //freopen("testdata.in","r",stdin);
     78     n=read(),m=read();
     79     for(int i=1;i<=n;++i){
     80         int x=read()+1,y=read()+1;
     81         p[i]=(node){x,y,i,true};
     82         cmax(lx,x),cmax(ly,y);
     83     }
     84     while(m--){
     85         int k=read(),x=read()+1,y=read()+1;
     86         ++n,p[n]=node(x,y,n,k&1);
     87         cmax(lx,x),cmax(ly,y);
     88     }
     89     memcpy(a+1,p+1,sizeof(node)*n);
     90     memset(ans,inf,sizeof(ans));
     91     check(),CDQ(1,m);
     92     for(int i=1;i<=n;++i)
     93     p[i]=a[i],p[i].x=lx-p[i].x+1;
     94     check(),CDQ(1,m);
     95     for(int i=1;i<=n;++i)
     96     p[i]=a[i],p[i].y=ly-p[i].y+1;
     97     check(),CDQ(1,m);
     98     for(int i=1;i<=n;++i)
     99     p[i]=a[i],p[i].y=ly-p[i].y+1,p[i].x=lx-p[i].x+1;
    100     check(),CDQ(1,m);
    101     for(int i=1;i<=n;++i)
    102     if(!a[i].f) print(ans[i]);
    103     Ot();
    104     return 0;
    105 }
  • 相关阅读:
    Codeforces Round #613 选讲
    Codeforces Round #612 选讲
    Codeforces917E
    一道题20
    LOJ#2244. 「NOI2014」起床困难综合症
    求欧拉回路
    *LOJ#2134. 「NOI2015」小园丁与老司机
    vim操作命令
    常见问题解决
    CentOS7下如何修改mysql的数据目录
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9459595.html
Copyright © 2020-2023  润新知