• Luogu P5416 [CTSC2016]时空旅行


    题目
    简化题意:你需要维护(n)个集合,集合元素为二元组((x,v))。集合(i)的产生方式是以某个原有集合(p_i)为样本,扩展或删除一个元素后得到新集合。有(q)次询问,每次给出(y)并指定一个集合(i),要求从集合(i)中找出一个元素,最小化((x−y)^2+v)
    先拆式子((x-y)^2+v=x^2-2xy+y^2+v),令其等于(k)(x^2+y^2-2xy+v=k)
    移项得(2yx+k=y^2+x^2+v),可以看作是((x,x^2+y^2+v))这一决策点,(2y)为斜率,(k)就为(y)轴截距。所以这个可以维护凸壳来解决。
    我们知道每一个元素在(dfs)序中会以一段一段区间的形式出现。
    每个点不管加入还是删除元素都会造成一个新的区间,所以区间总数是(O(n))的。
    将元素按照(x)升序排序后插入线段树,每个节点维护一个凸壳。
    询问按(y)升序排序,可以使得每次操作可是直接取上一次凸壳最前面的值。

    #include<bits/stdc++.h>
    #define LL long long
    #define db double
    #define pb push_back
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    #define INF 1e18
    using namespace std;
    const int N=500007;
    int L[N<<2],R[N<<2],t[N],dfn[N],T[N],n,m,Time;
    LL C[N],ans[N],val[N];
    vector<int>G[N],al[N],ar[N],w[N<<2];
    struct node{LL x,val,id;}a[N];
    int cmp(int a,int b){return val[a]<val[b];}
    int operator<(node a,node b){return a.val<b.val;}
    LL min(LL a,LL b){return a<b? a:b;}
    db K(int x ,int y){return (val[x]*val[x]+C[x]-val[y]*val[y]-C[y])/(db)(val[x]-val[y]);}
    void dfs(int u,int fa)
    {
        dfn[u]=++Time;
        if(T[u]>0) al[T[u]].pb(Time);
        if(T[u]<0) ar[-T[u]].pb(Time-1);
        for(int i=G[u].size()-1,v;~i;--i) if((v=G[u][i])^fa) dfs(v,u);
        if(T[u]>0) ar[T[u]].pb(Time);
        if(T[u]<0) al[-T[u]].pb(Time+1);
    }
    void build(int p,int l,int r)
    {
        L[p]=0,R[p]=-1;
        if(l==r) return ;
        build(ls,l,mid),build(rs,mid+1,r);
    }
    void update(int p,int l,int r,int ql,int qr,int P)
    {
        if(ql==l&&r==qr)
        {
    	while(w[p].size()<=R[p]+5) w[p].pb(0);
    	if(L[p]<=R[p]&&val[w[p][R[p]]]==val[P])
    	{
    	    if(C[w[p][R[p]]]<=C[P]) return ;
    	    --R[p];
    	}
    	while(L[p]<R[p]&&K(w[p][R[p]],P)<K(w[p][R[p]],w[p][R[p]-1])) --R[p];
    	w[p][++R[p]]=P;
    	return ;
        }
        if(qr<=mid) update(ls,l,mid,ql,qr,P);
        else if(ql>mid) update(rs,mid+1,r,ql,qr,P);
        else update(ls,l,mid,ql,mid,P),update(rs,mid+1,r,mid+1,qr,P);
    }
    LL query(int p,int l,int r,int x,LL t,LL sum)
    {
        LL ans=INF;
        while(L[p]<R[p]&&K(w[p][L[p]],w[p][L[p]+1])<=2.0*t) ++L[p];
        if(L[p]<=R[p]&&w[p].size()>0) ans=(t-val[w[p][L[p]]])*(t-val[w[p][L[p]]])+C[w[p][L[p]]];
        ans=min(ans,sum);
        if(l==r) return ans;
        return x<=mid? query(ls,l,mid,x,t,ans):query(rs,mid+1,r,x,t,ans);
    }
    int main()
    {
        int i,j,k,u,x,opt,l,r;
        scanf("%d%d%lld",&n,&m,&C[0]);
        for(i=1;i<n;++i) scanf("%d%d%d",&opt,&u,&x),G[u].pb(i),(opt? (T[i]=-x):(T[i]=x,scanf("%lld%d%d%lld",&val[x],&u,&u,&C[x])));
        dfs(0,0),build(1,1,n);
        for(i=1;i<=n;++i) t[i]=i;
        sort(t+1,t+n+1,cmp),update(1,1,n,1,n,0);
        for(i=1;i<=n;++i) for(k=t[i],j=0;j<al[k].size();++j) if((l=al[k][j])<=(r=ar[k][j])) update(1,1,n,l,r,k);
        for(i=1;i<=m;++i) scanf("%lld%lld",&a[i].x,&a[i].val),a[i].id=i;
        sort(a+1,a+m+1);
        for(i=1;i<=m;++i) ans[a[i].id]=query(1,1,n,dfn[a[i].x],a[i].val,INF);
        for(i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    docker入门
    IAR屏蔽警告的方法
    在MDK 中忽略(suppress) 某一个警告
    stm32 F40x CCM数据区的使用
    如何理解Stand SPI Dual SPI 和Quad SPI??
    stm32F1在sram中调试运行代码
    stm32低功耗的一点总结
    C语言中__attribute__ ((at())绝对定位的应用
    系统栈和任务栈——freertos
    软件模拟spi的注意事项
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11519553.html
Copyright © 2020-2023  润新知