洛谷 P5416 [CTSC2016] 时空旅行

洛谷 P5416 [CTSC2016] 时空旅行

https://www.luogu.com.cn/problem/P5416

用三维坐标描述宇宙中各个星球的位置,初始的编号为 \(0\) 的时空中,人类存在与地球 \((0,0,0)\) 上,其他的时空都是由一个现有的时空发展而来,一个时空在发生了一个事件后会发展成为另一个时空(原来的时空不发生变化).第 \(i\) 个时空可以描述为以下两种形式之一

  • \(fr,id,x,y,z,c\) ,表示第 \(i\) 个时空由 \(fr\) 号时空发展而来,人类殖民了编号为 \(id\) 的星球,它的坐标是 \((x,y,z)\) ,在这个星球上调查的花费为 \(c\) .

    保证 \(id\) 两两不同且 \(0 < id < n\) , \(0 \le fr < i, |x|,|y|,|z| \le 10^6, 0 \le c \le 10^{12}\) .

  • \(1,fr,id\) ,表示第 \(i\) 个时空由 \(fr\) 号时空发展而来,人类放弃了编号为 \(id\) 的星球,保证编号为 \(fr\) 的时空中 \(id\) 星球处于被殖民状态,且 \(id>0\) . \(0 \le fr<i\)

小R要在进行 \(m\) 次调查,第 \(i\) 次调查会前往 \(s_i\) 号时空,并传送到 \(x\) 坐标为 \(x_i\) 的某个点上,然后选择一个星球进行调查,一次调查的花费为 \(d^2+c\) ,其中 \(d\) 为传送位置与星球坐标之间的欧几里得距离, \(c\) 为选择的星球的调查费用.求每次调查的最小花费.

\(n,m \le 5 \times 10^5\)

Tutorial

https://www.cnblogs.com/Tiw-Air-OAO/p/12408531.html

显然, \(y,z\) 不影响答案,所以花费可以表示为 \((x-x_i)^2+c=-2x_ix+x_i^2+x^2+c\) ,也就是斜率优化的形式.

考虑时空的树形结构上,一个星球的贡献范围可以表示为一个子树的根节点开始,不经过那些表示删除掉这个星球的节点的连通块.将它表示在dfs序上.假如这个星球被删除了 \(x\) 次,那么就会产生 \(x+1\) 个区间,也就是说总区间数是 \(O(n)\) 的.

使用线段树分治,在外部对斜率排序,时间复杂度 \(O(n \log n)\)

Code

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define fi first
#define se second
#define SZ q[u].size()
using namespace std;
inline char nc()
{
//	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T &x)
{
	x=0; int f=1,ch=nc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
	x*=f;
}
typedef long long ll;
typedef pair<int,int> pii;
const ll inf=1e18;
const int maxn=5e5+50;
const int maxm=5e5+50;
int n,m;
int x[maxn]; ll c[maxn];
int s[maxm],x0[maxm];
int r[maxn]; bool op[maxn];
ll an[maxm];
int p;
int dfc;
int ed[maxn];
int st[maxn];
int ord[maxn];
int pos[maxn];
int head[maxn];
vector<int> rec[maxn];
vector<pii> range;
struct edge
{
	int to,nex;
	edge(int to=0,int nex=0):to(to),nex(nex){}
};
vector<edge> G;
inline void addedge(int u,int v)
{
	G.push_back(edge(v,head[u])),head[u]=G.size()-1;
}
inline bool invalid(int u,int v,int w)
{
	return (c[v]-c[u])*(x[w]-x[v])>=(c[w]-c[v])*(x[v]-x[u]);
}
namespace seg
{
	const int maxnode=maxn<<2;
	int pt[maxnode];
	vector<int> q[maxnode];
	void update(int u,int l,int r,int ql,int qr,int qv)
	{
		if(l==ql&&r==qr)
		{
			if(SZ&&x[q[u][SZ-1]]==x[qv]) return;
			while(SZ>1&&invalid(q[u][SZ-2],q[u][SZ-1],qv)) q[u].pop_back();
			q[u].push_back(qv);
			return;
		}
		int mid=(l+r)>>1;
		if(qr<=mid) update(lson,ql,qr,qv);
		else if(ql>mid) update(rson,ql,qr,qv);
		else
		{
			update(lson,ql,mid,qv);
			update(rson,mid+1,qr,qv);
		 } 
	}
	inline bool Cmin(ll &x,ll y) {return x>y?x=y,1:0;}
	ll query(int u,int l,int r,int qp,int x0)
	{
		ll re=inf;
		while(pt[u]+1<SZ&&x0*2ll*(x[q[u][pt[u]+1]]-x[q[u][pt[u]]])>=(c[q[u][pt[u]+1]]-c[q[u][pt[u]]])) ++pt[u];
		if(SZ) 
		{
			re=(ll)x0*x0-2ll*x0*x[q[u][pt[u]]]+c[q[u][pt[u]]];
		}
		if(l==r)
		{
			return re;
		}
		int mid=(l+r)>>1;
		if(qp<=mid) return min(re,query(lson,qp,x0));
		else return min(re,query(rson,qp,x0));
	}
}
void dfs(int u)
{
	st[u]=++dfc;
	for(int i=head[u];~i;i=G[i].nex)
	{
		int v=G[i].to; 
		dfs(v);
	}
	ed[u]=dfc;
}
inline int cmp0(const int &a,const int &b)
{
	if(x[a]!=x[b]) return x[a]<x[b];
	return c[a]<c[b];
}
inline int cmp1(const int &a,const int &b)
{
	return st[a]<st[b];
}
inline int cmp2(const int &a,const int &b)
{
	return x0[a]<x0[b];
}
int main()
{
//	freopen("travel.in","r",stdin);
//	freopen("travel.out","w",stdout);
	read(n),read(m),read(c[0]);
	memset(pos,-1,sizeof(pos)),pos[0]=0;
	memset(head,-1,sizeof(head));
	for(int i=1;i<n;++i)
	{
		read(op[i]);
		if(op[i]==0)
		{
			int fr,y,z; read(fr),read(r[i]),read(x[r[i]]),read(y),read(z),read(c[r[i]]);
			c[r[i]]+=(ll)x[r[i]]*x[r[i]]; 
			pos[r[i]]=i;
			addedge(fr,i);
		}
		else
		{
			int fr; read(fr),read(r[i]);
			rec[r[i]].push_back(i);
			addedge(fr,i);
		}
	}
	dfs(0);
	for(int i=0;i<=n;++i) if(pos[i]!=-1)
	{
		ord[++p]=i;
	}
	sort(ord+1,ord+p+1,cmp0);
	int cnt=0;
	for(int i=1;i<=p;++i)
	{
		int x=ord[i];
		range.clear();
		int now=st[pos[x]];
		if(rec[x].size()) sort(rec[x].begin(),rec[x].end(),cmp1);
		for(int j=0;j<rec[x].size();++j)
		{
			int u=rec[x][j];
			if(now<st[u]) range.push_back(make_pair(now,st[u]-1));
			now=ed[u]+1;
		}
		if(now<=ed[pos[x]]) range.push_back(make_pair(now,ed[pos[x]]));
		for(int j=0;j<range.size();++j)
		{
			int l=range[j].fi,r=range[j].se;
//			debug("%d %d %d %lld\n",l,r,::x[x],c[x]); 
			seg::update(1,1,n,l,r,x);
			++cnt;
		}
	}
//	debug("%d\n",cnt);
	for(int i=1;i<=m;++i)
	{
		ord[i]=i;
		read(s[i]),read(x0[i]);
	}
	sort(ord+1,ord+m+1,cmp2);
	for(int i=1;i<=m;++i)
	{
		int u=ord[i];
		an[u]=seg::query(1,1,n,st[s[u]],x0[u]);
	}
	for(int i=1;i<=m;++i)
	{
		printf("%lld\n",an[i]);
	}
	return 0;
}
posted @ 2020-05-07 20:49  LJZ_C  阅读(207)  评论(0编辑  收藏  举报