dtoi2679「SDOI2016」游戏

题意:

     Alice 和 Bob 在玩一个游戏。

     游戏在一棵有 $n$ 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 $123456789123456789$。
     有时,Alice 会选择一条从 $s$ 到 $t$ 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 $r$,若 $r$ 与 $s$ 的距离是 $\mathrm{dis}$,那么Alice 在点 $r$ 上添加的数字是 $a\cdot \mathrm{dis}+b$。

     有时,Bob 会选择一条从 $s$ 到 $t$ 的路径。他需要先从这条路径上选择一个点,再从那个点上选择一个数字。

     Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。

     Bob 需要你帮他找出他能够选择的最小的数字。

     $ n \leq 100000 $,$ m \leq 100000 $,$ \left| a \right| \leq 10000 $。

题解:

     直观的感受题目在做什么,实际上就是相当于在一段路径上插入一个线段,再求最小值,比较容易意识到是树链剖分+线段树维护线段。

     由于建立线段树是用dfs序建立的,考虑在树上的某一段重链,随着距离变化 $1$,显然dfs序也会变化 $1$,当然dfs序不等于距离,但是是线性关系,所以显然可以以dfs序作为横坐标,然后用线段树维护线段。

     然而打完树剖线段树之后,一试样例,读入都错了,才意识到这题是有边权的...

     那怎么办?现在距离变化 $w$,dfs序才变化 $1$,如何解决?可以修改一下dfs序的求法,同一条重链中,相邻两个点的dfs序可以由原来的变化 $1$ 强行改为变化 $w$,不同重链中随意(可以保留原来的变化 $1$)。然后这样就能得到一个新的dfs序,所有的操作在他们上面做,当然线段取值也只能由他们产生。

     接下来具体说一下这题中如何用线段树来维护线段,首先线段树动态开点,然后更新的时候,先找到对应的区间,对于两条线段,首先先找到“至少在这个区间的一半以上区域”更为优秀的那条线段,然后将它放在这个节点上,接下来再将另外一个线段往两个儿子的某一个儿子传下去。查询由于是区间查询,不仅要查询对应节点及其子节点的最优值,还要考虑这些节点的所有祖先所造成的贡献,可以判断一下区间相交之类的关系然后将端点代入计算。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
using namespace std;
const long long INF=123456789123456789ll;
int n,m,fa[22][100002],ct,cnt=1,dp[100002];
long long dep[100002],tim=1,d[100002];
typedef struct{
    int zlt,xzd,zjds,xzz;
    long long dfn;
}P;
typedef struct{
    int to,w;
}PP;
typedef struct{
    int ls,rs;
    long long minx,maxx,k,b,Min;
}XDS;
P p[100002];
XDS xds[5000002];
vector<PP>g[100002];
void dfs1(int x,int y){
    p[x].zjds=1;fa[0][x]=y;dp[x]=dp[y]+1;
    int Max=0,maxn=-1,w=0;
    for (int i=0;i<g[x].size();i++)
    if (g[x][i].to!=y)
    {
        dep[g[x][i].to]=dep[x]+g[x][i].w;
        dfs1(g[x][i].to,x);p[x].zjds+=p[g[x][i].to].zjds;
        if (p[g[x][i].to].zjds>Max)
        {
            Max=p[g[x][i].to].zjds;maxn=g[x][i].to;w=g[x][i].w;
        }
    }
    p[x].xzd=maxn;p[x].xzz=w;
}
void dfs2(int x,int y){
    p[x].dfn=d[++ct]=tim;
    if (p[y].xzd==x)p[x].zlt=p[y].zlt;else p[x].zlt=x;
    if (p[x].xzd!=-1){tim+=p[x].xzz;dfs2(p[x].xzd,x);}
    for (int i=0;i<g[x].size();i++)
    if (g[x][i].to!=y && g[x][i].to!=p[x].xzd){tim++;dfs2(g[x][i].to,x);}
}
int lca(int x,int y){
    if (dp[x]<dp[y])swap(x,y);
    int k=dp[x]-dp[y];
    for (int i=0;i<=20;i++)
    if ((1<<i)&k)x=fa[i][x];
    if (x==y)return x;
    for (int i=20;i>=0;i--)
    if (fa[i][x]!=fa[i][y])
    {
        x=fa[i][x];y=fa[i][y];
    }
    return fa[0][x];
}
long long jiaodian(long long k1,long long b1,long long k2,long long b2){
    return (b2-b1)/(k1-k2);
}
void hb(int root,long long begin,long long end){
    if (begin==end)
    {
        xds[root].minx=xds[root].maxx=begin;
        if (xds[root].k==INF)xds[root].Min=INF;else xds[root].Min=xds[root].k*begin+xds[root].b;
    }
    else
    {
        xds[root].minx=min(xds[xds[root].ls].minx,xds[xds[root].rs].minx);
        xds[root].maxx=max(xds[xds[root].ls].maxx,xds[xds[root].rs].maxx);
        xds[root].Min=min(xds[xds[root].ls].Min,xds[xds[root].rs].Min);
        if (xds[root].k<INF)xds[root].Min=min(xds[root].Min,min(xds[root].k*xds[root].minx+xds[root].b,xds[root].k*xds[root].maxx+xds[root].b));
    }
}
void build(int root,long long begin,long long end,long long wz){
    if (begin==end){xds[root].minx=xds[root].maxx=begin;return;}
    long long mid=(begin+end)/2;
    if (wz<=mid)
    {
        if (!xds[root].ls)xds[root].ls=++cnt;
        build(xds[root].ls,begin,mid,wz);
    }
    else
    {
        if (!xds[root].rs)xds[root].rs=++cnt;
        build(xds[root].rs,mid+1,end,wz);
    }
    hb(root,begin,end);
}
void gx(int root,long long begin,long long end,long long k,long long b){
    if (!root)return;
    if (xds[root].k==INF)
    {
        xds[root].k=k;xds[root].b=b;
        hb(root,begin,end);
        return;
    }
    if (xds[root].k==k)
    {
        xds[root].b=min(xds[root].b,b);
        hb(root,begin,end);
        return;
    }
    if (begin==end)
    {
        if (k*begin+b<xds[root].k*begin+xds[root].b)
        {
            xds[root].k=k;xds[root].b=b;
        }
        hb(root,begin,end);
        return;
    }
    long long mid=(begin+end)/2,jd=jiaodian(xds[root].k,xds[root].b,k,b);
    if (xds[root].k<k){swap(xds[root].k,k);swap(xds[root].b,b);}
    if (jd<=mid)
    {
        swap(xds[root].k,k);swap(xds[root].b,b);
        gx(xds[root].ls,begin,mid,k,b);
    }
    else gx(xds[root].rs,mid+1,end,k,b);
    hb(root,begin,end);
}
void gengxin(int root,long long begin,long long end,long long begin2,long long end2,long long k,long long b){
    if (begin>end2 || end<begin2 || !root)return;
    if (begin>=begin2 && end<=end2)
    {
        gx(root,begin,end,k,b);return;
    }
    long long mid=(begin+end)/2;
    gengxin(xds[root].ls,begin,mid,begin2,end2,k,b);gengxin(xds[root].rs,mid+1,end,begin2,end2,k,b);
    hb(root,begin,end);
}
long long chaxun(int root,long long begin,long long end,long long begin2,long long end2){
    if (begin>end2 || end<begin2 || !root)return INF;
    if (begin>=begin2 && end<=end2)return xds[root].Min;
    long long mid=(begin+end)/2,a1=INF,a2=INF;
    if (begin2<=begin && xds[root].k<INF)a1=xds[root].k*xds[root].minx+xds[root].b;
    else if(xds[root].k<INF)a1=xds[root].k*begin2+xds[root].b;
    if (end2>=end && xds[root].k<INF)a2=xds[root].k*xds[root].maxx+xds[root].b;
    else if(xds[root].k<INF)a2=xds[root].k*end2+xds[root].b;
    return min(min(chaxun(xds[root].ls,begin,mid,begin2,end2),chaxun(xds[root].rs,mid+1,end,begin2,end2)),min(a1,a2));
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        PP aa;aa.to=v;aa.w=w;
        g[u].push_back(aa);
        aa.to=u;
        g[v].push_back(aa); 
    }
    dfs1(1,0);dfs2(1,0);
    for (int i=0;i<5000002;i++){xds[i].Min=xds[i].minx=xds[i].k=xds[i].b=INF;xds[i].maxx=-INF;}
    for (int i=1;i<=n;i++)build(1,1,tim,d[i]);
    for (int i=1;i<=20;i++)
    for (int j=1;j<=n;j++)
    fa[i][j]=fa[i-1][fa[i-1][j]];
    while(m--)
    {
        int op;
        scanf("%d",&op);
        if (op==1)
        {
            int u,v,a,b;
            scanf("%d%d%d%d",&u,&v,&a,&b);
            int lc=lca(u,v);long long de=dep[u],d1=dep[u]-dep[lc];
            while(dep[u]>=dep[lc] && u)
            {
                int x,y=u;
                if (dep[p[u].zlt]<dep[lc])x=lc;else x=p[u].zlt;
                gengxin(1,1,tim,p[x].dfn,p[y].dfn,-a,b+(long long)a*(de-dep[x]+p[x].dfn));
                u=fa[0][p[u].zlt];
            }
            while(dep[v]>=dep[lc] && v)
            {
                int x,y=v;
                if (dep[p[v].zlt]<dep[lc])x=lc;else x=p[v].zlt;
                gengxin(1,1,tim,p[x].dfn,p[y].dfn,a,b+(long long)a*(d1+dep[x]-dep[lc]-p[x].dfn));
                v=fa[0][p[v].zlt];
            }
        }
        else
        {
            int u,v;long long ans=INF;
            scanf("%d%d",&u,&v);
            int lc=lca(u,v);
            while(dep[u]>=dep[lc] && u)
            {
                int x,y=u;
                if (dep[p[u].zlt]<dep[lc])x=lc;else x=p[u].zlt;
                ans=min(ans,chaxun(1,1,tim,p[x].dfn,p[y].dfn));
                u=fa[0][p[u].zlt];
            }
            while(dep[v]>=dep[lc] && v)
            {
                int x,y=v;
                if (dep[p[v].zlt]<dep[lc])x=lc;else x=p[v].zlt;
                ans=min(ans,chaxun(1,1,tim,p[x].dfn,p[y].dfn));
                v=fa[0][p[v].zlt];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
posted @ 2021-02-17 21:04  1124828077ccj  阅读(70)  评论(0编辑  收藏  举报