zoukankan      html  css  js  c++  java
  • 天使玩偶「CDQ分治」

    天使玩偶「CDQ分治」

    题目描述

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

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

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

    输入格式

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

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

    再接下来 (m) 行,每行三个非负整数 (t,x_i,y_i)​。

    • 如果 (t=1),则表示 Ayu 又回忆起了一个可能埋着玩偶的点 ((x_i,y_i))
    • 如果 (t=2),则表示 Ayu 询问如果她在点 ((x_i,y_i)),那么在已经回忆出来的点里,离她近的那个点有多远

    输出格式

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

    输入输出样例

    输入 #1

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

    输出 #1

    1 
    2
    

    数据规模与约定

    对于 (100\%) 的数据 保证 (1≤n,m≤3×10^5,0≤x_i,y_i≤10^6)

    思路分析

    一开始是真没想到和 (CDQ) 分治能有什么关系

    • 题目中已经给出了距离公式,即 (operatorname{dist}(A,B)=|A_x-B_x|+|A_y-B_y|),绝对值很麻烦,所以我们为了方便处理,先只算位于一个点左下方的点的距离,这时候就可以去掉绝对值了,式子就成了 ((A_x+A_y)-(B_x+B_y)),其中 (A_x+A_y) 是确定的,所以我们只需求出 (B_x+B_y) 的最大值
    • 然后你会神奇地发现,这时候你需要维护三个关系——出现时间(因为离线处理),x值,y值(保证在左下角),这不就成了三维偏序吗?就可以用 (CDQ) 分治做了,只不过树状数组里维护的是最大值而不是前缀和
    • 对于不在左下角的点,我们完全可以讲网格进行翻转,把其他角转成左下角
    • 另外洛谷上的时间限制卡得很紧,分治时用快排是过不去的,需要改成归并排序

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define N 300005
    #define M 1000005
    #define R register
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int inf = 0x3f3f3f3f;
    int n,m,mx,my,c[M];
    struct node{
    	int id,x,y,key,opt;//key记录答案,opt记录是用来更新的还是查询的
    }a[M],p[M],t[M];//p是用于进行翻转的,a是用于更新答案的,t是用于归并排序的
    inline bool cmp(node aa,node bb){return aa.x==bb.x ? aa.y<bb.y : aa.x<bb.x;}//第一维其实不需要再排序了,只需要排序第二维就行
    void update(int x,int y){
    	for(;x <= my;x += x&(-x))c[x] = max(c[x],y);
    }
    int query(int x){
    	int res = 0;
    	for(;x;x -= x&(-x))res = max(res,c[x]);
    	return res;
    }
    void clear(int x){
    	for(;x<=my;x += x&(-x)){
    		if(!c[x])break;
    		c[x] = 0;
    	}
    }
    void CDQ(int l,int r){
    	if(l==r)return;
    	int mid = (l+r)>>1;
    	CDQ(l,mid),CDQ(mid+1,r);
    	int i = l,j = mid+1;
    	while(j<=r){
    		while(i<=mid&&a[i].x <= a[j].x){
    			if(a[i].opt==1)update(a[i].y,a[i].x+a[i].y);//树状数组更新x+y的值
    			i++;
    		}
    		if(a[j].opt == 0){
    			int tmp = query(a[j].y);
    			if(tmp) p[a[j].id].key=min(p[a[j].id].key,a[j].x+a[j].y-tmp);
    		}
    		j++;
    	}
    	for(R int k = l;k < i;k++)if(a[k].opt==1)clear(a[k].y);//记得清空
    	i = l,j = mid+1;//归并排序
    	int k = l-1;
    	while(j<=r){
    		while(i<=mid&&cmp(a[i],a[j]))t[++k] = a[i++];
    		t[++k] = a[j++];
    	}
    	while(j<=r)t[++k] = a[j++];
    	while(i<=mid)t[++k] = a[i++];
    	for(R int i = l;i <= r;i++)a[i] = t[i];
    }
    void Init(){
    	for(R int i = 1;i <= n;i++)a[i] = p[i];
    }
    int main(){
    	n=read(),m=read();
    	for(R int i = 1;i <= n;i++){
    		int x=read()+1,y=read()+1;
    		mx=max(mx,x),my=max(my,y);
    		p[i]=node{i,x,y,x+y,1};
    	}
    	while(m--) {
    		int op=read(),x=read()+1,y=read()+1;
    		mx=max(mx,x),my=max(my,y);
    		if(op==1) p[++n]=node{n,x,y,x+y,1};
    		else p[++n]=node{n,x,y,inf,0};
    	}
    	Init();
    	CDQ(1,n);
    	for(R int i = 1;i <= n;i++) p[i].x=mx-p[i].x+1;//翻转操作
    	Init();
    	CDQ(1,n);
    	for(R int i = 1;i <= n;i++) p[i].y=my-p[i].y+1;
    	Init();
    	CDQ(1,n);
    	for(R int i = 1;i <= n;i++) p[i].x=mx-p[i].x+1;
    	Init();
    	CDQ(1,n);
    	for(R int i = 1;i <= n;i++) if(p[i].opt==0) printf("%d
    ",p[i].key);
    	return 0;
    }
    
  • 相关阅读:
    一句sql语句删除重复记录
    Remoting测试
    关于委托
    遍历打印文件夹中的word文档
    c# string类型的一个理解误区
    viewstate
    依赖注入与工厂模式Demo
    memcache配置实践
    201732 C#链接数据库实现登陆
    观察者设计模式[伪]
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13644900.html
Copyright © 2011-2022 走看看