时空旅行

题面Luogu

题面LOJ

我为什么来写这一篇题解?

因为我对线段树分治的理解,在这一题的基础上增强了不少!

线段树分治,就是可以将一些不好删除的东西变成区间加

但是这个东西要满足可加性

比如说时间这个东西,一会加上一个值,一会再把这个值减掉

这时我们可以找到这个值存在的区间,这样我们可以直接在线段树上覆盖这个区间来做加法

本题既是用线段树分治\(dfs\)序,发现我们删除一个殖民地就是在子树中删除全部的这个星球

加入一个殖民地也是对于子树来说的,而子树的\(dfs\)序是连续的

我们可以用线段树维护\(dfs\)序,每个节点存个凸包

这样我们查某一个点的时候,一路查下去,找个最优的就行了

注意这里一路上的凸包不必合并,凸包只是优化找到最值的过程,我们完全可以在好几个符合条件的凸包上找到最值

然后把几个最值取个最大值即可

注意拆区间的时候,\(set\)\(lower\_bound\)判断区间是否相等

没啥额

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pa pair<int,int>
#define mk(x,y) make_pair(x,y)
#define fi first
#define se second
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=5e5+5;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    vector<pa> tb[N*4];int zhi[N*4];
    long double K(pa a,pa b){if(b.fi==a.fi)return 1e18;return 1.0*(b.se-a.se)/(b.fi-a.fi);}
    bool comp(pa a,pa b,pa c){return K(a,b)>=K(b,c);}
    void in(int x,pa v){
        while(tb[x].size()>1&&comp(tb[x][tb[x].size()-2],*tb[x].rbegin(),v))tb[x].pop_back();
        tb[x].push_back(v);
    }
    void ins(int x,int l,int r,int ql,int qr,pa v){
        if(ql<=l&&r<=qr)return in(x,v),void();
        int mid=l+r>>1;
        if(ql<=mid)ins(ls,l,mid,ql,qr,v);
        if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
    }
    int qu(int x,int px){
        if(!tb[x].size())return inf;
        while(zhi[x]+1<tb[x].size()&&K(tb[x][zhi[x]],tb[x][zhi[x]+1])<=px)zhi[x]++;
        return tb[x][zhi[x]].se-tb[x][zhi[x]].fi*px+px*px;
    }
    int query(int x,int l,int r,int pos,int px){
        if(l==r)return qu(x,px);
        int mid=l+r>>1,ret=qu(x,px);
        if(pos<=mid)ret=min(ret,query(ls,l,mid,pos,px));
        else ret=min(ret,query(rs,mid+1,r,pos,px));
        return ret;
    }
    #undef ls
    #undef rs
}xds;
int n,m;
struct node{int x,c,y;set<pa> st;}sa[N];
bool com(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
struct E{int to,nxt;}e[N*2];
int head[N],rp,tp[N],id[N];
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
int dfn[N],idf[N],dfm[N],cnt;
void dfs_fi(int x){
    dfn[x]=++cnt;idf[cnt]=x;
    for(int i=head[x];i;i=e[i].nxt)dfs_fi(e[i].to);
    dfm[x]=cnt;
}
void erase(int id,int l,int r){
    set<pa>::iterator it=--sa[id].st.lower_bound(mk(l,r));
    if(next(it)->fi==l&&next(it)!=sa[id].st.end())it=next(it);
    int s=it->fi,t=it->se;sa[id].st.erase(it);
    if(s<l)sa[id].st.insert(mk(s,l-1));
    if(r<t)sa[id].st.insert(mk(r+1,t));
}
void dfs_se(int x){
    if(tp[x]==0)sa[id[x]].st.insert(mk(dfn[x],dfm[x]));
    else erase(id[x],dfn[x],dfm[x]);
    for(int i=head[x];i;i=e[i].nxt)dfs_se(e[i].to);
}
struct Q{int id,s,x;}q[N];
bool comp(Q a,Q b){return a.x<b.x;}
int ans[N];
signed main(){
    n=read();m=read();sa[0].c=read();sa[0].x=0;
    fo(i,2,n){
        int t=read(),fa=read()+1,idd=read();
        add_edg(fa,i);
        if(t==0){
            sa[idd].x=read();int sb=read();sb=read();
            sa[idd].c=read();tp[i]=0;id[i]=idd;
        }
        else tp[i]=1,id[i]=idd;
    }
    dfs_fi(1);dfs_se(1);
    fo(i,0,n)sa[i].y=sa[i].x*sa[i].x+sa[i].c,sa[i].x*=2;
    sort(sa,sa+n+1,com);
    fo(i,0,n){
        pa v=mk(sa[i].x,sa[i].y);
        for(pa j:sa[i].st)xds.ins(1,1,n,j.fi,j.se,v);
    }
    fo(i,1,m)q[i].s=read()+1,q[i].x=read(),q[i].id=i;
    sort(q+1,q+m+1,comp);
    fo(i,1,m)ans[q[i].id]=xds.query(1,1,n,dfn[q[i].s],q[i].x);
    fo(i,1,m)printf("%lld\n",ans[i]);
}
posted @ 2022-01-10 08:32  fengwu2005  阅读(114)  评论(0编辑  收藏  举报