zoukankan      html  css  js  c++  java
  • 洛谷 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 imes 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
    ",l,r,::x[x],c[x]); 
    			seg::update(1,1,n,l,r,x);
    			++cnt;
    		}
    	}
    //	debug("%d
    ",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
    ",an[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用.NET发送EMail小程序示例
    Log4Net使用手册
    深入继承之抽象类和接口综合分析及完整案列解说(二)
    Prototype 1.4.0源码详细解释脚本代码全文注释
    深入继承之抽象类和接口综合分析及完整案列解说(一)
    关于如何理解 not exists 的好比喻 not exists = not in;exists= in
    一些直接访问 的 外国 SCI 期刊地址
    ∩∈∪≠ 制作PPT 时 数学符号
    Can I make a userdefined function/procedure to return a result set
    IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/12845516.html
Copyright © 2011-2022 走看看