码迷,mamicode.com
首页 > 其他好文 > 详细

[Violet]天使玩偶/SJY摆棋子

时间:2018-12-09 12:11:49      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:坐标   ems   旋转   fine   eof   oid   ==   class   owb   

传送门

题目大意就是先给定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;
}

[Violet]天使玩偶/SJY摆棋子

标签:坐标   ems   旋转   fine   eof   oid   ==   class   owb   

原文地址:https://www.cnblogs.com/captain1/p/10090225.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!