洛谷P4169 天使玩偶 CDQ分治

还是照着CDQ的思路来。

但是有一些改动:

  • 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的。怎么办?旋转!做4次就好了。
  • 统计的不是和,而是——max!理由如下:

    设当前点是(x,y),目标点是(x',y'),那么所求的|x-x'|+|y-y'|首先用旋转大法化为x-x'+y-y',然后我们发现这个东西其实就是x+y-x'-y'=(x+y)-(x'+y'),而x+y我们是已知的。所以我们求一下max(x'+y')即可。具体实现是对树状数组魔改。

 

然后交上去发现狂T不止...

疯狂优化!首先把树状数组的max从作死的M改成了所有坐标中最大的mm,发现不行,跑去看题解。

发现不能每次sort,而且还要删点。

然后学习了一波操作之后,成功的到达了91分...还是有3个点死活过不了。把题解拿下来一交,发现居然也T了一个点,哈哈哈。

听从雨菲的建议,果断开O2,A了。

看代码理解删点优化和魔改树状数组。

  1 // luogu-judger-enable-o2
  2 #include <cstdio>
  3 #include <algorithm>
  4 using namespace std;
  5 const int M = 1000009,N = 600010,INF=0x3f3f3f3f;
  6 inline int read()
  7 {
  8     int ans=0;char ch=getchar();
  9     while(ch<'0'||ch>'9') ch=getchar();
 10     while(ch>='0'&&ch<='9') ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
 11     return ans;
 12 }
 13 inline int lowbit(int x){return x&(-x);}
 14 int ta[M+1],n,mm,ans[N];int p,rx,ry;
 15 inline void add(int x,int a)
 16 {
 17     if(x<=0) return;
 18     for(int i=x;i<=ry;i+=lowbit(i)) ta[i]=max(ta[i],a);
 19     return;
 20 }
 21 inline int getsum(int x)
 22 {
 23     if(x<=0)return 0;int ans=-INF;
 24     for(int i=x;i>0;i-=lowbit(i)) ans=max(ans,ta[i]);
 25     return ans;
 26 }
 27 inline void del(int x)
 28 {
 29     if(x<=0) return;
 30     for(int i=x;i<=ry;i+=lowbit(i)) ta[i]=-INF;
 31     return;
 32 }
 33 struct Node
 34 {
 35     int x,y,k=-INF,t,type;
 36 }node[N],temp[N],f[N];
 37 inline bool cmp_t(Node a,Node b){return a.t<b.t;}
 38 inline void rotate()
 39 {
 40     for(int i=1;i<=n;i++)
 41     {
 42         int t=f[i].x;
 43         f[i].x=mm-f[i].y;
 44         f[i].y=t;
 45     }
 46     return;
 47 }
 48 void CDQ(int l,int r)
 49 {
 50     if(l==r) return;
 51     int mid=(l+r)>>1;
 52     CDQ(l,mid);CDQ(mid+1,r);
 53     int i=l,j=mid+1,t=0;
 54     while(i<=mid||j<=r)
 55     {
 56         if(j>r||(i<=mid&&node[i].x<=node[j].x))
 57         {
 58             if(node[i].type==1) add(node[i].y,node[i].x+node[i].y);
 59             temp[++t]=node[i++];
 60         }
 61         else
 62         {
 63             if(node[j].type>1) {node[j].k=max(node[j].k,getsum(node[j].y));
 64             ans[node[j].t]=min(ans[node[j].t],node[j].x+node[j].y-node[j].k);}
 65             ///if(node[j].type>1) node[j].k=min(node[j].k,(node[j].x+node[j].y-getsum(node[j].y)));
 66             temp[++t]=node[j++];
 67         }
 68     }
 69     t=0;
 70     for(j=l;j<i;j++) if(node[j].type==1) del(node[j].y);
 71     for(i=l;i<=r;i++) node[i]=temp[++t];
 72     return;
 73 }
 74 
 75 inline void Delete()
 76 {
 77     rx=ry=p=0;
 78     for(int i=1;i<=n;i++) if(f[i].type==2) rx=max(rx,f[i].x),ry=max(ry,f[i].y);
 79     for(int i=1;i<=n;i++) if(f[i].x<=rx&&f[i].y<=ry) node[++p]=f[i];
 80     return;
 81 }
 82 int main()
 83 {
 84     fill(ta,ta+M,-INF);
 85     int n2=read(),n3=read(),x,y,flag;
 86     for(int i=1;i<=n2;i++)
 87     {
 88         x=read()+1;y=read()+1;
 89         f[++n].x=x;
 90         f[n].y=y;
 91         f[n].type=1;
 92         f[n].t=n;
 93         mm=max(mm,x);
 94         mm=max(mm,y);
 95     }
 96     for(int i=1;i<=n3;i++)
 97     {
 98         flag=read();x=read()+1;y=read()+1;
 99         f[++n].x=x;
100         f[n].y=y;
101         f[n].type=flag;
102         f[n].t=n;
103         mm=max(mm,x);
104         mm=max(mm,y);
105     }
106     mm++;
107     fill(ans+1,ans+n+1,INF);
108     for(y=1;y<=4;y++)
109     {
110         Delete();
111         ry++;
112         //for(int i=1;i<=p;i++) printf("%d %d %d\n",node[i].type,node[i].x,node[i].y);
113         CDQ(1,p);
114         //for(int i=1;i<=n;i++)if(f[i].type==2)printf("%d ",ans[i]);
115         //printf("\n");
116         rotate();
117     }
118 
119     for(int i=1;i<=n;i++)
120     {
121         if(f[i].type==2) printf("%d\n",ans[i]);
122     }
123 
124     return 0;
125 }
126 /**
127 1 3
128 3 1
129 2 5 5
130 1 6 4
131 2 5 5
132 */
伪AC代码:

 

posted @ 2018-04-21 18:50  huyufeifei  阅读(223)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜