• 洛谷 P4088 [USACO18FEB] Slingshot P(线段树+二维数点)


    题目链接

    题意:有一个数轴,上面有 (n) 个传送门,使用第 (i) 个传送门,你可以从 (x_i) 走到 (y_i),花费的时间为 (t_i) 秒。你的速度为 (1) 格/秒,有 (m) 次询问,每次你要从 (a_i) 走到 (b_i),最多使用一次传送门,问最少需要多少秒。
    (1 leq n,m leq 10^5)(0 leq a_i,b_i leq 10^9)

    我果然是要退役了,用未去重的数组离散化(
    很显然对于第 (j) 个询问使用第 (i) 个传送门的情况,需要 (|x_i-a_j|+|y_i-b_j|+t_i) 秒的时间。
    看那个绝对值有点像曼哈顿距离……这就启发我们将题目转换为:平面上有 (n) 个点,第 (i) 个点位于 ((x_i,y_i)),有点权 (t_i)。有 (m) 次询问,要求与 ((a_i,b_i)) 的曼哈顿距离加上点的权值最小的点。
    为什么要这么转化呢?看到平面,我们就想到二维数点。将这 (n+m) 个点按 (x) 坐标排序,暴力将绝对值拆开,分四种情况更新答案就可以了。
    注意事项:对每个询问,记得赋初值 (|b_i-a_i|)

    //Coded by tzc_wk
    /*
    数据不清空,爆零两行泪。
    多测不读完,爆零两行泪。
    边界不特判,爆零两行泪。
    贪心不证明,爆零两行泪。
    D P 顺序错,爆零两行泪。
    大小少等号,爆零两行泪。
    变量不统一,爆零两行泪。
    越界不判断,爆零两行泪。
    调试不注释,爆零两行泪。
    溢出不 l l,爆零两行泪。
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define giveup(...) return printf(__VA_ARGS__),0;
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define mask(a)		(1ll<<(a))
    #define maskx(a,x)	((a)<<(x))
    #define _bit(a,x)	(((a)>>(x))&1)
    #define _sz(a)		((int)(a).size())
    #define filei(a)	freopen(a,"r",stdin);
    #define fileo(a)	freopen(a,"w",stdout);
    #define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    #define put(x)		putchar(x)
    #define eoln        put('
    ')
    #define space		put(' ')
    #define y1			y_chenxiaoyan_1
    #define y0			y_chenxiaoyan_0
    #define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-')	neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c))	x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    inline void print(int x){
    	if(x<0){
    		putchar('-');
    		print(abs(x));
    		return;
    	}
    	if(x<=9)	putchar(x+'0');
    	else{
    		print(x/10);
    		putchar(x%10+'0');
    	}
    }
    inline int qpow(int x,int e,int _MOD){
    	int ans=1;
    	while(e){
    		if(e&1)	ans=ans*x%_MOD;
    		x=x*x%_MOD;
    		e>>=1;
    	}
    	return ans;
    }
    int _abs(int x){
    	return (x<0)?-x:x;
    }
    int n,m;
    struct ycxakioi{
    	int x,y,t;
    	friend bool operator <(ycxakioi ycx,ycxakioi tzc){
    		return ycx.x<tzc.x;
    	}
    } p[200005];
    struct query{
    	int x,y,id,ans;
    	friend bool operator <(query x,query y){
    		return x.x<y.x;
    	}
    } q[200005];
    int keyx[200005],xc,yc,keyy[200005],hsx[200005],cx,hsy[200005],cy;
    struct SegTree{
    	struct node{
    		int l,r,mn;
    	} s[200005<<2];
    	inline void init(){
    		fz(i,0,(200005<<2)-1)	s[i].mn=0x3f3f3f3f3f3f3f3fll;
    	}
    	inline void build(int k,int l,int r){
    		s[k].l=l;s[k].r=r;
    		if(l==r)	return;
    		int mid=(l+r)>>1;
    		build(k<<1,l,mid);
    		build(k<<1|1,mid+1,r);
    	}
    	inline void modify(int k,int ind,int x){
    		if(s[k].l==s[k].r){
    			s[k].mn=min(s[k].mn,x);
    			return;
    		}
    		int mid=(s[k].l+s[k].r)>>1;
    		if(ind<=mid)	modify(k<<1,ind,x);
    		else			modify(k<<1|1,ind,x);
    		s[k].mn=min(s[k<<1].mn,s[k<<1|1].mn);
    	}
    	inline int query(int k,int l,int r){
    		if(l<=s[k].l&&s[k].r<=r){
    			return s[k].mn;
    		}
    		int mid=(s[k].l+s[k].r)>>1;
    		if(r<=mid)	return query(k<<1,l,r);
    		else if(l>mid)	return query(k<<1|1,l,r);
    		else		return min(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    	}
    } s1,s2,s3,s4;
    int anss[200005];
    signed main(){
    //	filei("P4088_5.in");
    	n=read(),m=read();
    	fz(i,1,n){
    		p[i].x=read();
    		p[i].y=read();
    		p[i].t=read();
    		keyx[++xc]=p[i].x;
    		keyy[++yc]=p[i].y;
    	}
    	fz(i,1,m){
    		q[i].x=read();
    		q[i].y=read();
    		q[i].id=i;
    		q[i].ans=_abs(q[i].y-q[i].x);
    		keyx[++xc]=q[i].x;
    		keyy[++yc]=q[i].y;
    	}
    	sort(keyx+1,keyx+xc+1);sort(keyy+1,keyy+yc+1);
    	keyx[0]=0x3f3f3f3f;keyy[0]=0x3f3f3f3f;
    	fz(i,1,xc)	if(keyx[i]!=keyx[i-1])	hsx[++cx]=keyx[i];
    	fz(i,1,yc)	if(keyy[i]!=keyy[i-1])	hsy[++cy]=keyy[i];
    	fz(i,1,n)	p[i].x=lower_bound(hsx+1,hsx+cx+1,p[i].x)-hsx;
    	fz(i,1,n)	p[i].y=lower_bound(hsy+1,hsy+cy+1,p[i].y)-hsy;
    	fz(i,1,m)	q[i].x=lower_bound(hsx+1,hsx+cx+1,q[i].x)-hsx;
    	fz(i,1,m)	q[i].y=lower_bound(hsy+1,hsy+cy+1,q[i].y)-hsy;
    //	fz(i,1,n)	cout<<p[i].x<<" "<<p[i].y<<" "<<p[i].t<<endl;
    //	fz(i,1,m)	cout<<q[i].x<<" "<<q[i].y<<endl;
    	sort(p+1,p+n+1);
    	sort(q+1,q+m+1);
    	s1.build(1,1,cy);s2.build(1,1,cy);s3.build(1,1,cy);s4.build(1,1,cy);
    	s1.init();s2.init();s3.init();s4.init();
    	p[n+1].x=0x3f3f3f3f;
    	int cur=1;
    	fz(i,1,m){
    //		if(i>=5000)	cerr<<i<<endl;
    		while(p[cur].x<=q[i].x){
    			s1.modify(1,p[cur].y,-hsy[p[cur].y]-hsx[p[cur].x]+p[cur].t);
    			s2.modify(1,p[cur].y,hsy[p[cur].y]-hsx[p[cur].x]+p[cur].t);
    			cur++;
    		}
    		q[i].ans=min(q[i].ans,s1.query(1,1,q[i].y)+hsx[q[i].x]+hsy[q[i].y]);
    		q[i].ans=min(q[i].ans,s2.query(1,q[i].y,cy)+hsx[q[i].x]-hsy[q[i].y]);
    	}
    	cur=n;
    	fd(i,m,1){
    //		cerr<<i<<endl;
    		while(p[cur].x>=q[i].x&&cur>=1){
    			s3.modify(1,p[cur].y,hsy[p[cur].y]+hsx[p[cur].x]+p[cur].t);
    			s4.modify(1,p[cur].y,-hsy[p[cur].y]+hsx[p[cur].x]+p[cur].t);
    			cur--;
    		}
    		q[i].ans=min(q[i].ans,s4.query(1,1,q[i].y)-hsx[q[i].x]+hsy[q[i].y]);
    		q[i].ans=min(q[i].ans,s3.query(1,q[i].y,cy)-hsx[q[i].x]-hsy[q[i].y]);
    	}
    	fz(i,1,m)	anss[q[i].id]=q[i].ans;
    	fz(i,1,m)	cout<<anss[i]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    左旋一个字符串和手摇反转法
    LCS
    游戏服务器学习_1
    面试题_带答案_2
    面试题_带答案
    安卓_13
    安卓_12activity
    安卓_12
    多盟_1
    安卓没删干净导致报错
  • 原文地址:https://www.cnblogs.com/ET2006/p/12731774.html
Copyright © 2020-2023  润新知