• luogu P5416 [CTSC2016]时空旅行


    luogu

    uoj

    注意到用这个集合产生方式可以构建出一个树型结构,并且每个加入/删除元素都是对应的一个子树的范围,对应到dfs序上就是每次对一个区间内的集合加入/删除元素,所以可以线段树分治,把每种元素的出现区间整出来

    把答案柿子((x-x_0)^2+c)拆开,得到(x^2-2x*x_0+{x_0}^2+c),然后每个元素就相当于斜率为(-2x),截距为(x^2+c)的直线,所以线段树每个节点维护凸壳,要用的时候直接查对应横坐标的值.如果直接做是两个(log)的,但是因为要答案最小,所以可以按照斜率从大到小((x)从小到大)的顺序插入元素对应的直线,然后按照(x_0)从小到大查询,这样由于插入和查询的单调性所以可以少掉一个log

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=5e5+10;
    LL rd()
    {
    	LL x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    struct node
    {
    	LL x,y;
    }a[N],qr[N];
    vector<int> ti[N],e[N];
    LL an[N];
    int n,m,q,fa[N],ty[N],sz[N],dfn[N],tt,sb[N];
    bool cmp1(int aa,int bb){return a[aa].x!=a[bb].x?a[aa].x<a[bb].x:a[aa].x*a[aa].x+a[aa].y>a[bb].x*a[bb].x+a[bb].y;}
    bool cmp2(int aa,int bb){return qr[aa].x<qr[bb].x;}
    void dfs(int x)
    {
    	dfn[x]=++tt,sz[x]=1;
    	ti[ty[x]].push_back(dfn[x]);
    	vector<int>::iterator it;
    	for(it=e[x].begin();it!=e[x].end();++it)
    	{
    		int y=*it;
    		dfs(y),sz[x]+=sz[y];
    	}
    	ti[ty[x]].push_back(dfn[x]+sz[x]);
    }
    struct line
    {
    	db k,b;
    	line(){}
    	line(LL x,LL y){k=-2*x,b=x*x+y;}
    };
    db jiao(line aa,line bb){return (bb.b-aa.b)/(aa.k-bb.k);}
    struct HULL
    {
    	vector<line> qu;
    	int hd,tl;
    	HULL(){hd=0,tl=-1;}
    	void inst(line aa)
    	{
    		if(hd<=tl&&qu[tl].k==aa.k) qu.pop_back(),--tl;
    		while(hd<tl&&jiao(aa,qu[tl])<=jiao(qu[tl],qu[tl-1])) qu.pop_back(),--tl;
    		qu.push_back(aa),++tl;
    	}
    	LL quer(LL x)
    	{
    		while(hd<tl&&x>=jiao(qu[hd],qu[hd+1])) ++hd;
    		return hd<=tl?(LL)round(qu[hd].k*(db)x+qu[hd].b):1ll<<50;
    	}
    }hl[N<<2];
    #define mid ((l+r)>>1)
    int ps[N];
    void setli(int o,int l,int r,int ll,int rr,line x)
    {
    	if(ll<=l&&r<=rr){hl[o].inst(x);return;}
    	if(ll<=mid) setli(o<<1,l,mid,ll,rr,x);
    	if(rr>mid) setli(o<<1|1,mid+1,r,ll,rr,x);
    }
    void bui(int o,int l,int r)
    {
    	if(l==r){ps[l]=o;return;}
    	bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
    }
    
    int main()
    {
    	n=rd(),q=rd();
    	a[++m]=(node){0,rd()};
    	ty[1]=1;
    	for(int i=2;i<=n;++i)
    	{
    		int op=rd();
    		fa[i]=rd()+1;
    		int ii=rd()+1;
    		e[fa[i]].push_back(i);
    		ty[i]=ii;
    		m=max(m,ii);
    		if(op==0)
    		{
    			a[ii].x=rd();
    			rd(),rd();
    			a[ii].y=rd();
    		}
    	}
    	dfs(1);
    	for(int i=1;i<=n;++i) sb[i]=i;
    	sort(sb+1,sb+n+1,cmp1);
    	for(int i=1;i<=n;++i)
    	{
    		int ii=sb[i],nn=ti[ii].size();
    		for(int j=0;j+1<nn;j+=2)
    			if(ti[ii][j]<=ti[ii][j+1]-1)
    				setli(1,1,n,ti[ii][j],ti[ii][j+1]-1,line(a[ii].x,a[ii].y));
    	}
    	for(int i=1;i<=q;++i)
    	{
    		int y=rd()+1,x=rd();
    		qr[i]=(node){x,y};
    	}
    	for(int i=1;i<=q;++i) sb[i]=i;
    	sort(sb+1,sb+q+1,cmp2);
    	bui(1,1,n);
    	for(int i=1;i<=q;++i)
    	{
    		int ii=sb[i],es=qr[ii].y;
    		LL y=qr[ii].x;
    		int o=ps[dfn[es]];
    		an[ii]=1ll<<50;
    		while(o)
    		{
    			an[ii]=min(an[ii],y*y+hl[o].quer(y));
    			o>>=1;
    		}
    	}
    	for(int i=1;i<=q;++i) printf("%lld
    ",an[i]);
    	return 0; 
    }
    
  • 相关阅读:
    vi
    head
    uniq
    sort
    所谓静态绑定
    债务
    不确
    tar
    VMWare虚拟系统上网设置 及 三种模式详解
    awk
  • 原文地址:https://www.cnblogs.com/smyjr/p/11507520.html
Copyright © 2020-2023  润新知