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; }