zoukankan      html  css  js  c++  java
  • 题解-P4169 [Violet]天使玩偶/SJY摆棋子

    (Large atural) P4169 [Violet]天使玩偶,SJY摆棋子 原题链接

    题意

    由于特殊原因,加了个题意简述

    一开始有 (n) 个关键点 ((a,b))。然后有 (T) 个操作:

    • 多出一个关键点 ((a,b))
    • 询问如果我站在 ((x,y)),最近的关键点距离我多远。(这里的距离是曼哈顿距离

    (n,Tle 3 imes 10^5),以及 (0le a,b,x,yle 10^6)

    解法

    一开始的 (n) 个点直接当修改操作。

    曼哈顿距离表示是 (|x_1-x_2|+|y_1-y_2|),这显然不好算。一般对于曼哈顿距离有两种解决方案,一种是转成切比雪夫距离,另一种是拆绝对值。我们看到这题有修改操作,想到拆绝对值更方便一些。

    对于询问操作,我们分四种情况讨论(最近的点在我的左上 / 右上 / 左下 / 右下)。看到题目有三个维度 (x,y,t),我们可以想到 CDQ分治


    下面以点在我右上角为例。

    对于每一个询问 ((x,y)),其它点处我的距离是:

    [|x-a|+|y-b|=a-x+b-y=a+b-x-y ]

    (x,y) 是不会变的,我们只用找到 (a+b) 的最小值即可。

    按照 CDQ分治 的套路,我们已经把区间一分为二。对于每个区间,我们以 (x) 为第一关键字, (y) 为第二关键字排序操作。

    我们的目的是,查询 ((x,y)) 右上角的点中 (a+b) 最小值,我们可以用线段树维护。

    然后每次把 (age x) 的修改都加入(给 (b) 这个位置更新 (a+b) 权值)。这个时候所有的关键点肯定都在 ((x,y))右边。而查询 (ysim inf) 就保证了关键点在 ((x,y))上方,所以就查询到了右上角啦~

    最后根据套路,记得清空线段树


    其它三个方位都是类似的,只用稍微改一下排序方式、枚举方式、线段树更新权值、线段树查询区间就行了。看似很复杂,但只要多在纸上画画图就可以清晰地打完题目了。

    代码

    注意因为一开始的关键点都当修改操作了,所以存操作的数组空间得开两倍

    数组要清空为极大值。

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;++i)
    using namespace std;
    const int n7=601234,t7=4012345,hug=1000000;
    struct dino{int sys,x,y,id;}qq[n7];
    int n,T,tre[t7],ans[n7];
    
    int rd(){
        int shu=0;char ch=getchar();
        while( !isdigit(ch) )ch=getchar();
        while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+(ch^48),ch=getchar();
        return shu;
    }
    
    void updat(int o,int l,int r,int id,int x){
    	if(l==r){tre[o]=x;return;}
    	int mid=(l+r)>>1;
    	if(id<=mid)updat(o<<1,l,mid,id,x);
    	else updat(o<<1|1,mid+1,r,id,x);
    	tre[o]=min(tre[o<<1],tre[o<<1|1]);
    } 
    
    int query(int o,int l,int r,int L,int R){
    	if(L<=l&&r<=R)return tre[o];
    	int mid=(l+r)>>1,fin=INT_MAX;
    	if(L<=mid)  fin=query(o<<1,l,mid,L,R);
    	if(R>=mid+1)fin=min(fin, query(o<<1|1,mid+1,r,L,R) );
    	return fin;
    }
    
    bool cmp1(dino p,dino q){return p.x==q.x?p.y>q.y:p.x>q.x;}
    
    bool cmp2(dino p,dino q){return p.x==q.x?p.y>q.y:p.x<q.x;}
    
    bool cmp3(dino p,dino q){return p.x==q.x?p.y<q.y:p.x<q.x;}
    
    bool cmp4(dino p,dino q){return p.x==q.x?p.y<q.y:p.x>q.x;}
    
    void CDQ(int l,int r){
    	if(l==r||r<=n)return;
    	int mid=(l+r)>>1,L;
    	CDQ(l,mid),CDQ(mid+1,r);
    
    	//点在我站位右上角 
    	sort(qq+l,qq+mid+1,cmp1);
    	sort(qq+mid+1,qq+r+1,cmp1);
    	L=l;
    	rep(i,mid+1,r){
    		if(qq[i].sys==1)continue;
    		while(qq[L].x>=qq[i].x&&L<=mid){
    			if(qq[L].sys==1)updat(1,0,hug,qq[L].y,qq[L].x+qq[L].y);
    			L++;
    		}
    		ans[ qq[i].id ]=min(ans[ qq[i].id ],query(1,0,hug,qq[i].y,hug)-qq[i].x-qq[i].y);
    	}
    	rep(i,l,L-1){
    		if(qq[i].sys==1)updat(1,0,hug,qq[i].y,tre[0]);
    	}
    	
    	//点在我站位左上角 
    	sort(qq+l,qq+mid+1,cmp2);
    	sort(qq+mid+1,qq+r+1,cmp2);
    	L=l;
    	rep(i,mid+1,r){
    		if(qq[i].sys==1)continue;
    		while(qq[L].x<=qq[i].x&&L<=mid){
    			if(qq[L].sys==1)updat(1,0,hug,qq[L].y,-qq[L].x+qq[L].y);
    			L++;
    		}
    		ans[ qq[i].id ]=min(ans[ qq[i].id ],query(1,0,hug,qq[i].y,hug)+qq[i].x-qq[i].y);
    	}
    	rep(i,l,L-1){
    		if(qq[i].sys==1)updat(1,0,hug,qq[i].y,tre[0]);
    	}
    	
    	//点在我站位左下角 
    	sort(qq+l,qq+mid+1,cmp3);
    	sort(qq+mid+1,qq+r+1,cmp3);
    	L=l;
    	rep(i,mid+1,r){
    		if(qq[i].sys==1)continue;
    		while(qq[L].x<=qq[i].x&&L<=mid){
    			if(qq[L].sys==1)updat(1,0,hug,qq[L].y,-qq[L].x-qq[L].y);
    			L++;
    		}
    		ans[ qq[i].id ]=min(ans[ qq[i].id ],query(1,0,hug,0,qq[i].y)+qq[i].x+qq[i].y);
    	}
    	rep(i,l,L-1){
    		if(qq[i].sys==1)updat(1,0,hug,qq[i].y,tre[0]);
    	}
    	
    	//点在我站位右下角 
    	sort(qq+l,qq+mid+1,cmp4);
    	sort(qq+mid+1,qq+r+1,cmp4);
    	L=l;
    	rep(i,mid+1,r){
    		if(qq[i].sys==1)continue;
    		while(qq[L].x>=qq[i].x&&L<=mid){
    			if(qq[L].sys==1)updat(1,0,hug,qq[L].y,qq[L].x-qq[L].y);
    			L++;
    		}
    		ans[ qq[i].id ]=min(ans[ qq[i].id ],query(1,0,hug,0,qq[i].y)-qq[i].x+qq[i].y);
    	}
    	rep(i,l,L-1){
    		if(qq[i].sys==1)updat(1,0,hug,qq[i].y,tre[0]);
    	}
    }
    
    int main(){
    	n=rd(),T=rd();
    	rep(i,1,n)qq[i]=(dino){1,rd(),rd(),0};
    	rep(i,n+1,n+T)qq[i]=(dino){rd(),rd(),rd(),i-n};
    	memset(ans,0x3f,sizeof ans);
    	memset(tre,0x3f,sizeof tre);
    	CDQ(1,n+T);
    	rep(i,1,T){
    		if(ans[i]^ans[0])printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    树的遍历
    动态规划之背包问题
    Dijkstra算法
    最短路径
    关于数学公式Markdown
    子集数
    O、Θ、Ω
    AT212 P-CASカードと高橋君
    vector的使用方法
    P3512 [POI2010]PIL-Pilots 单调队列的应用
  • 原文地址:https://www.cnblogs.com/BlankAo/p/14507879.html
Copyright © 2011-2022 走看看