jzoj 3196.【HNOI模拟题】物理 dp+k-d tree

本文深入解析了一种基于坐标和区间的高效信息传递算法,通过排序和数据结构优化,实现了大规模数据集上的快速信息传播计算。文章详细介绍了算法的实现过程,包括关键的数据结构设计和优化策略,以及具体的代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于题目描述过于沙雕,这里给出题目大意:
nnn个人站在数轴的非负半轴上,其中一个是sg(自己理解),他站在0号点上。
对于其他的n−1n-1n1个人,第iii个人用三元组(xi,yi,li)(x_i,y_i,l_i)(xi,yi,li)描述,说明这个人站在lil_ili点上,并有一个区间[xi,yi][x_i,y_i][xi,yi]来描述它的听觉范围。
题目给定一个LLL,第iii个人能把信息传到第jjj个人,满足li&gt;ljl_i&gt;l_jli>ljli−lj&lt;=Ll_i-l_j&lt;=Llilj<=L且他们的听觉范围有交,传一次信息要1秒。sg的听觉范围是[0,inf][0,inf][0,inf]。询问每个人听到信息后把信息告诉sg要多少秒。
1≤n≤250000,0≤xi,yi,li≤2000000000,1≤L≤2000000000,xi≤yi1≤n≤250000,0≤x_i,y_i,l_i≤2000000000,1≤L≤2000000000,x_i≤y_i1n2500000xi,yi,li20000000001L2000000000xiyi

分析:
我们以lil_ili为关键字排序,lil_ili相同以编号排序。
因为只有右边的人可以传个左边的人,设f[i]f[i]f[i]表示左数第iii个人传到sg需要的时间。
我们可以用一个坐标(xi,yi)(x_i,y_i)(xi,yi)描述一个点,它的权值为f[i]f[i]f[i]
对于f[j]f[j]f[j]的转移,需要把横坐标在[0,yj][0,y_j][0,yj],纵坐标在[xj,inf][x_j,inf][xj,inf]的点的权值取min。如果有一个点转移不到(距离超过LLL),把这个点权值改为infinfinf

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

const int maxn=250007;
const int inf=2e9;

using namespace std;

int n,L,cnt,k,root;
int f[maxn],c[maxn*2],ans[maxn];

struct data{
	int x,y,l,num;
}a[maxn];

struct rec{
    int d[2];
};

bool operator ==(rec a,rec b)
{
    return (a.d[0]==b.d[0]) && (a.d[1]==b.d[1]); 
}

struct node{
	int l,r,data;
}t[maxn*50];

bool cmp(data a,data b)
{
	if (a.l==b.l) return a.num<b.num;
	return a.l<b.l;
}

void change(int &p,rec l,rec r,rec a,int k,int op)
{
    if (!p) p=++cnt;
    if (l==r)
    {
        t[p].data=k;
        return;
    }
    int mid=(l.d[op]+r.d[op])/2;
    rec L=l,R=r;
    L.d[op]=mid+1,R.d[op]=mid;
    if (a.d[op]<=mid) change(t[p].l,l,R,a,k,op^1);
                 else change(t[p].r,L,r,a,k,op^1);
    t[p].data=inf;
    if (t[p].l) t[p].data=min(t[p].data,t[t[p].l].data); 
    if (t[p].r) t[p].data=min(t[p].data,t[t[p].r].data); 
}

void getmin(int p,rec l,rec r,rec a,rec b,int op)
{
	if (!p) return;
	if (t[p].data>=k) return;
    if ((l==a) && (r==b))
    {
    	k=min(k,t[p].data);
        return;
    }
    int mid=(l.d[op]+r.d[op])/2;
    rec L=l,R=r;
    L.d[op]=mid+1,R.d[op]=mid;
    if (b.d[op]<=mid) getmin(t[p].l,l,R,a,b,op^1);
    else if (a.d[op]>mid) getmin(t[p].r,L,r,a,b,op^1);
    else
    {
    	rec A=a,B=b;
    	A.d[op]=mid+1,B.d[op]=mid;
    	getmin(t[p].l,l,R,a,B,op^1);
    	getmin(t[p].r,L,r,A,b,op^1);
    }
}

int main()
{
	scanf("%d%d",&n,&L);
	for (int i=1;i<n;i++)
	{
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].l);
		a[i].num=i;
	}
	a[n]=(data){0,inf,0};
	for (int i=1;i<=n;i++) 
	{
		c[i]=a[i].x,c[i+n]=a[i].y;
	}
	sort(c+1,c+n*2+1);
	int size=unique(c+1,c+2*n+1)-c-1;
    for (int i=1;i<=n;i++)
    {
    	a[i].x=lower_bound(c+1,c+size+1,a[i].x)-c;
    	a[i].y=lower_bound(c+1,c+size+1,a[i].y)-c;
	}	
	sort(a+1,a+n+1,cmp);
	int j=1;
	f[1]=0;
	change(root,(rec){{1,1}},(rec){{size,size}},(rec){{a[1].x,a[1].y}},f[1],0);			
	for (int i=2;i<=n;i++)
	{
		while (a[i].l-a[j].l>L)
		{
			change(root,(rec){{1,1}},(rec){{size,size}},(rec){{a[j].x,a[j].y}},inf,0);
			j++;
		}
		k=inf;
		getmin(root,(rec){{1,1}},(rec){{size,size}},(rec){{1,a[i].x}},(rec){{a[i].y,size}},0);
		f[i]=min(k+1,inf);
		ans[a[i].num]=f[i];
		change(root,(rec){{1,1}},(rec){{size,size}},(rec){{a[i].x,a[i].y}},f[i],0);
	}
	for (int i=1;i<n;i++) 
	{
		if (ans[i]>=inf) printf("-1\n");
		            else printf("%d\n",ans[i]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值