[Violet]天使玩偶/SJY摆棋子
题目大意就是先给定n个点,然后m个操作,每次添加一个点或者查询离一个点最近的一个点是哪个点。
因为要求的是曼哈顿距离,所以我们先把式子转化一下,就是\((x_i + y_i) - (x_j + y_j)\),也就是对于查询的点,求出时间早于它,且\(x,y\)都小于它的点中\(x_i+y_i\)最大的一个。这个可以用树状数组维护最大值。
这个就是很简单的三维偏序,\(CDQ\)分治写一下就好了。不过这样只能找一个方向,一共有4个方向,每次用最大坐标分别减去横,纵坐标就可以实现旋转的效果了。
不过有点虚,这个理论的复杂度是\(O(4\times(n+m)log(n+m)logmax_y)\),好像怎么算都会超时……最后不得已之后不用\(sort\),改成用归并排序之后还得开\(O2\)才能过。
看一下代码。
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
const int M = 300005;
const int N = 1000005;
inline int read()
{
int ans = 0,op = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') op = -1;
ch = getchar();
}
while(ch >='0' && ch <= '9')
{
ans *= 10;
ans += ch - '0';
ch = getchar();
}
return ans * op;
}
inline void write(int x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
struct treearray
{
int c[N+10];
void add(int x,int v) {while(x <= N+2) c[x] = max(c[x],v),x += lowbit(x);}
int ask(int x) {int cur = 0;while(x) cur = max(cur,c[x]),x -= lowbit(x);return cur;}
void clear(int x) {while(x <= N+2) c[x] = 0,x += lowbit(x);}
}T;
struct node
{
int x,y,tim;
bool operator < (const node &g) const
{
return x < g.x;
}
}a[M<<1],b[M<<1],t[M<<1];
int n,m,cnt,op,Ti,ans[M];
void CDQ(int l,int r)
{
if(l == r) return;
int mid = (l+r) >> 1,p1 = l,p2 = mid+1;
CDQ(l,mid),CDQ(mid+1,r);
//sort(a+l,a+mid+1),sort(a+mid+1,a+r+1);
rep(i,l,r)
{
if(p2 > r || (p1 <= mid && a[p1].x <= a[p2].x))
{
t[i] = a[p1++];
if(!t[i].tim) T.add(t[i].y,t[i].x + t[i].y);
}
else
{
t[i] = a[p2++];
if(!t[i].tim) continue;
int k = T.ask(t[i].y);
if(k) ans[t[i].tim] = min(ans[t[i].tim],t[i].x + t[i].y - k);
}
}
rep(i,l,mid) if(!a[i].tim) T.clear(a[i].y);
rep(i,l,r) a[i] = t[i];
}
int main()
{
memset(ans,0x3f,sizeof(ans));
n = read(),m = read();
rep(i,1,n) b[++cnt].x = read()+1,b[cnt].y = read()+1;
rep(i,1,m)
{
op = read();
if(op == 1) b[++cnt].x = read()+1,b[cnt].y = read()+1;
else b[++cnt].x = read()+1,b[cnt].y = read()+1,b[cnt].tim = ++Ti;
}
rep(i,1,cnt) a[i] = b[i];
CDQ(1,cnt);
rep(i,1,cnt) a[i] = b[i],a[i].x = N - a[i].x;
CDQ(1,cnt);
rep(i,1,cnt) a[i] = b[i],a[i].y = N - a[i].y;
CDQ(1,cnt);
rep(i,1,cnt) a[i] = b[i],a[i].x = N - a[i].x,a[i].y = N - a[i].y;
CDQ(1,cnt);
rep(i,1,Ti) write(ans[i]),enter;
return 0;
}
当你意识到,每个上一秒都成为永恒。