luogu P5416 [CTSC2016]时空旅行

Posted smyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",an[i]);
    return 0; 

以上是关于luogu P5416 [CTSC2016]时空旅行的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P5416 [CTSC2016]时空旅行(线段树分治)

@loj - 2987@ 「CTSC2016」时空旅行

[CTSC2016]时空旅行

[UOJ198][CTSC2016]时空旅行

[CTSC2016]时空旅行(线段树+凸包)

uoj198CTSC2016时空旅行