BZOJ2716 & NKOJ2739:[Violet 3]天使玩偶——题解

同样方便非权限玩家,NKOJ有这道题。

http://oi.nks.edu.cn/zh/Problem/Details/2739

http://www.lydsy.com/JudgeOnline/problem.php?id=2716

样例输入

2 3
1 1
2 3
2 1 2
1 3 3
2 4 2

样例输出

1

2

————————————————————————————————

整整一个上午的时间,终于DEBUG出来了,原来是因为我数组开小了……

首先我们很容易想到一个三元组(t,x,y),其中t为操作时间。

默认最开始给定的一些点的操作为插入,且时间优先级均高于其他的点。

那么显然就是三维偏序,CDQ可以上了。

给t排个序,边归并x边树状数组记录y,然后查即可……

但是我们怎么求dis啊?

我们有种玄学的方法叫做分情况讨论。

分成四种情况:

对于(x,y)(x1,y1)的dis:

x+y-(x1+y1)      (x>x1,y>y1)

x-y-(x1-y1)        (x>x1,y<y1)

-x+y-(y1-x1)      (x<x1,y>y1)

-x-y-(-x1-y1)      (x<x1,y<y1)

其中括号内的东西就是我们要用树状数组来维护的东西,显然当括号内的东西最大的时候我们的距离有最小值。

那么就变成了维护区间最大值的问题了,显然树状数组是能够胜任这项工作的。

具体的实现方法看我代码吧……不好描述。

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=500010;
const int N=1000010;
const int INF=10*N;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==‘-‘;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct rem{
    int t;
    int x;
    int y;
    int pos;
}q[2*M],tmp[2*M];
int m,n,cnt=0,ans[M],tree[N],maxy=-1;
bool cmp(rem a,rem b){
    return (a.t<b.t||(a.t==b.t&&a.x<b.x)||(a.t==b.t&&a.x==b.x&&a.y<b.y)||(a.t==b.t&&a.x==b.x&&a.y==b.y&&a.pos<b.pos));
}
inline int lowbit(int t){return t&(-t);}
void add(int x,int y){
    for(int i=x;i<=maxy;i+=lowbit(i))tree[i]=max(tree[i],y);
    return;
}
int query(int x){
    int res=-INF;
    for(int i=x;i>0;i-=lowbit(i))res=max(res,tree[i]);
    return res;
}
void cdq(int l,int r){
    if(l>=r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    for(int i=l,j=l,p=mid+1;i<=r;i++){
    if(j<=mid&&(p>r||q[j].x<=q[p].x))tmp[i]=q[j++];
    else tmp[i]=q[p++];
    }
    ///////////
    for(int i=l;i<=r;i++){
    q[i]=tmp[i];
    if(q[i].t<=mid&&!q[i].pos)add(q[i].y,q[i].x+q[i].y);
    if(q[i].t>mid&&q[i].pos)ans[q[i].pos]=min(ans[q[i].pos],q[i].x+q[i].y-query(q[i].y));
    }
    for(int i=l;i<=r;i++){
    if(q[i].t<=mid&&!q[i].pos){
        for(int j=q[i].y;j<=maxy;j+=lowbit(j))tree[j]=-INF;
    }
    }
    ///////////
    for(int i=l;i<=r;i++){
    if(q[i].t<=mid&&!q[i].pos)add(maxy-q[i].y,q[i].x-q[i].y);
    if(q[i].t>mid&&q[i].pos)ans[q[i].pos]=min(ans[q[i].pos],q[i].x-q[i].y-query(maxy-q[i].y));
    }
    for(int i=l;i<=r;i++){
    if(q[i].t<=mid&&!q[i].pos){
        for(int j=maxy-q[i].y;j<=maxy;j+=lowbit(j))tree[j]=-INF;
    }
    }
    ///////////
    for(int i=r;i>=l;i--){
    if(q[i].t<=mid&&!q[i].pos)add(q[i].y,q[i].y-q[i].x);
    if(q[i].t>mid&&q[i].pos)ans[q[i].pos]=min(ans[q[i].pos],-q[i].x+q[i].y-query(q[i].y));
    }
    for(int i=l;i<=r;i++){
    if(q[i].t<=mid&&!q[i].pos){
        for(int j=q[i].y;j<=maxy;j+=lowbit(j))tree[j]=-INF;
    }
    }
    ///////////
    for(int i=r;i>=l;i--){
    if(q[i].t<=mid&&!q[i].pos)add(maxy-q[i].y,-q[i].x-q[i].y);
    if(q[i].t>mid&&q[i].pos)ans[q[i].pos]=min(ans[q[i].pos],-q[i].x-q[i].y-query(maxy-q[i].y));
    }
    for(int i=l;i<=r;i++){
    if(q[i].t<=mid&&!q[i].pos){
        for(int j=maxy-q[i].y;j<=maxy;j+=lowbit(j))tree[j]=-INF;
    }
    }
    ///////////
    return;
}
void clear(){
    maxy++;
    for(int i=1;i<=cnt;i++)ans[i]=INF;
    for(int i=1;i<=maxy;i++)tree[i]=-INF;
    return;
}
int main(){
    n=read();
    m=read();
    for(int i=1;i<=n;i++){
    q[i].x=read()+1;
    q[i].y=read()+1;
    q[i].t=i;
    maxy=max(maxy,q[i].y);
    }
    for(int i=n+1;i<=m+n;i++){
    int w=read();
    if(w==1){
        q[i].x=read()+1;
        q[i].y=read()+1;
        q[i].t=i;
        maxy=max(maxy,q[i].y);
    }else{
        q[i].x=read()+1;
        q[i].y=read()+1;
        q[i].t=i;
        q[i].pos=++cnt;
        maxy=max(maxy,q[i].y);
    }
    }
    sort(q+1,q+m+n+1,cmp);
    clear();
    cdq(1,m+n);
    for(int i=1;i<=cnt;i++)printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-11-14 15:30:47

BZOJ2716 & NKOJ2739:[Violet 3]天使玩偶——题解的相关文章

【BZOJ 2716/2648】 [Violet 3]天使玩偶

2716: [Violet 3]天使玩偶 kd-tree模板题. ①首先依次按照每一维(即先按照x,再按照y,再按照x-多维同理)将点存在一棵二叉树中: 先求出以当前维数为关键字的中间点是谁(用到nth_element这个函数,可以直接把排名为k的放在第k位上,不保证其他有序:nth_element(a+1,a+1+k,a+1+n,cmp)) 为了一会儿查询中求估价函数方便,需要记录一下当前节点的子树中各维的极值(max,min) ②插入操作与splay的插入操作同理. ③询问操作的本质是搜索+

BZOJ 2716: [Violet 3]天使玩偶

2716: [Violet 3]天使玩偶 Time Limit: 80 Sec  Memory Limit: 128 MBSubmit: 1473  Solved: 621[Submit][Status][Discuss] Description Input Output Sample Input & Output 样例过大,略 HINT Source Vani原创 欢迎移步 OJ2648 [Submit][Status][Discuss] CDQ分治,分类讨论拆绝对值的方式,分别查询最优值.

SJY摆棋子&amp;&amp;[Violet 3]天使玩偶

SJY摆棋子 https://www.lydsy.com/JudgeOnline/problem.php?id=2648 [Violet 3]天使玩偶 https://www.lydsy.com/JudgeOnline/problem.php?id=2716 参考博客:https://blog.csdn.net/Littlewhite520/article/details/78284697 KDtree模板题,带插入 1 #include<iostream> 2 #include<cst

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

题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶:或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远. 因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|A

BZOJ 2648 SJY摆棋子 / 2716 Violet 3 天使玩偶 K-D树

题目大意:平面上有一些点,问一个点周围离它最近的点的曼哈顿距离是多少.支持动态加点. 思路:CDQ分治可以离线解决,但是SJY是卡CDQ的,天使玩偶可以过.毕竟K-D树的O(sqrt(n))的时间复杂度摆在那. K-D树理解起来其实不难,有k个维度的时候,每一层按照一个维度排序,取出按照这个维度排序的中位数,当作这个块的根,然后将这个块分开.还有一个比较重要的东西就是估价函数,这个函数根据不同的题可能不同.股价函数的主要用途就是对搜索进行剪枝,如果估价函数就已经大于当前的最优答案了,那就不用搜这

【kd-tree】bzoj2716 [Violet 3]天使玩偶

#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 500001 #define INF 2147483647 #define KD 2//ά¶ÈÊý int qp[KD],disn; int n,root; bool dn; struct Node { int minn[KD],maxx[KD],p[KD]; int ch[2]; void Init(

[BZOJ2716][Violet 3]天使玩偶

试题描述 输入 输出 输入示例 第一个测试点,我就不拿来占页面了= = 输出示例 同上 数据规模及约定 = =题目中给的范围不对...交上去RE...我目测大概 N, M ≤ 600000,xi, yi ≤ 107. 题解 出题人cnbb! 1.) 数据超大,时限 80 sec,出题人恶意卡测评机! 2.) 不能用任何读入优化. 3.) 数据范围还给错了! 4.) kd树模板删边题.[正经的题解只有这一句 #include <iostream> #include <cstdio>

【BZOJ】2648: SJY摆棋子 &amp; 2716: [Violet 3]天使玩偶(kdtree)

http://www.lydsy.com/JudgeOnline/problem.php?id=2716 http://www.lydsy.com/JudgeOnline/problem.php?id=2648 双倍经验题... kdtree裸题吧.....今天学了下kdtree...感觉挺简单的.... 其实就是对几何图形进行剖分建树,而特殊在于,x和y轴轮流剖....这样可以提供很好的性质以便于查找... (一开始脑补了个treap代替kdtree.....显然我脑残了....写到一半发现这

BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]

传送门 题意: 维护二维点集P,支持以下两个操作(1)插入点(x,y)(2)给定询问(x,y),求点集中离询问点最近的点距离定义为曼哈顿距离Dis(P1,P2)=|x1-x2|+|y1-y2|n,m<=500000x,y<=1000000 时间,$x$,$y$ $CDQ$分治里需要四个象限分类讨论,树状数组维护最大值 然后有两个象限是后缀和 然后跟$PoPoQQQ$学了一个神奇的技巧,树状数组加一个时间戳,就可以不用每次清空之前的操作了 #include <iostream> #i