小迟修马路
road.in/.out/.cpp
【问题描述】
⼩小迟生活的城市是1棵树(树指的是一个含有 n 个节点以及 n-1 条边的无向连通图),节点编号从 1 到 n,每条边拥有一个权值 value,表示通过这条边的时候你需要交纳的金钱(注意,有可能这个值为负数,也就是说你经过这条边的时候你可以赚钱)小迟是一个杰出的马路工,他居住在节点 s,他能够选择任意一个节点m,并将从节点 s 到节点 m 的简单路径(简单路径指的是不经过同一个节点两次)上的所有边的权值都修改为 0.现在小迟获得 q 个请求,每个请求都是以 a b 的形式给出,表示小迟的好朋友小早希望从节点 a 走简单路径到节点 b,小迟希望能最小化小早需要缴纳的钱。
需要注意的是,小迟获得的这 q 个请求是相互独立的,也就是说您只需要对于每一个请求,决定小迟的一个修路方案,使得小早需要缴纳的钱尽可能的少。
【输入格式】
输入文件名为 road.in。
第一行三个正整数为 n,q,s。
接下来 n-1 行,每行三个整数 x y z, 表示有一条边 (x,y),value 为 z。
接下来 q 行,每个两个正整数 a b,表示请求。
【输出格式】
输出文件名为 road.out。
Q 行,每行两个整数,表示需要缴纳的最少的钱。
【样例输入】
3 2 1
1 2 1
2 3 1
1 2
1 3
【样例输出】
0
0
【样例解释】
对于第一次询问 1 2, 小迟可以修从 1 到 2 的路,从而使得小早不需要
缴纳金钱;
对于第二次询问 1 3, 小迟可以修从 1 到 3 的路,从而使得小早不需要
缴纳金钱。
【数据规模及约定】
对于 30% 的数据,n≤1000,q≤1000.
对于 100% 的数据,1≤n,q≤200000,1≤x,y≤n,|z|≤1000.
题解:
LCA+树剖维护最大值。这题无根,为了方便以s为根,可以算出每个点到S的dis,然后考虑清零情况,S为x y的lca,y为lca,x为lca,x y的lca在S下方
对于第一种只能选择清左边或者清右边,对于第二三种,清到最小值就行,对于第四种与第一种类似,但是最后结果要再减去dis[lca(x,y)](考试的时候减了两倍,然后100->0)。
这是lca部分,剩下的就需要树剖维护dis中的最大值,再用底下点的dis减去就行
代码:
#include<iostream> #include<cstdio> #define lson k<<1,l,mid #define rson k<<1|1,mid+1,r #define ls k<<1 #define rs k<<1|1 #define mid ((l+r)>>1) using namespace std; const int N=200005,inf=2e9; int n,m,cnt,s,mi,tot; int head[N],fa[N][23],dis[N],dep[N]; int son[N],top[N],val[N],siz[N],id[N]; int tr[N<<2]; struct node{ int to,nxt,dis; }e[N<<1]; inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();} return w*s; } inline void add(int from,int to,int dis){ e[++cnt]=(node){to,head[from],dis}; head[from]=cnt; } void dfs(int x,int f,int di){ dep[x]=dep[f]+1; fa[x][0]=f; dis[x]=dis[f]+di;siz[x]=1; for(int i=1;(1<<i)<=dep[x];++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=f){ dfs(e[i].to,x,e[i].dis); siz[x]+=siz[e[i].to]; if(siz[e[i].to]>siz[son[x]])son[x]=e[i].to; } } void dfs2(int x,int topf){ top[x]=topf;id[x]=++tot;val[tot]=dis[x]; if(!son[x])return ; dfs2(son[x],topf); int y; for(int i=head[x];i;i=e[i].nxt){ y=e[i].to; if(y==fa[x][0]||y==son[x])continue; dfs2(y,y); } } inline int lca(int x,int y){ if(dep[x]>dep[y])x^=y^=x^=y; for(int i=21;i>=0;i--) if(dep[x]<=dep[fa[y][i]]) y=fa[y][i]; if(x==y)return x; for(int i=21;i>=0;--i){ if(fa[x][i]==fa[y][i])continue; x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } inline void update(int k){ tr[k]=max(tr[ls],tr[rs]); } void build(int k,int l,int r){ if(l==r){ tr[k]=val[l]; return ; } build(lson);build(rson); update(k); } int ask(int k,int l,int r,int x,int y){ if(l==x&&y==r){ return tr[k]; } if(y<=mid)return ask(lson,x,y); else if(x>mid)return ask(rson,x,y); else return max(ask(lson,x,mid),ask(rson,mid+1,y)); } void query(int x,int y){ mi=-inf; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); mi=max(ask(1,1,n,id[top[x]],id[x]),mi); x=fa[top[x]][0]; } if(dep[x]>dep[y])swap(x,y); mi=max(ask(1,1,n,id[x],id[y]),mi); } int main(){ freopen("road.in","r",stdin); freopen("road.out","w",stdout); n=read();m=read();s=read(); int x,y,z; for(int i=1;i<n;++i){ x=read();y=read();z=read(); add(x,y,z);add(y,x,z); } dfs(s,0,0); dfs2(s,s); build(1,1,n); int ans; while(m--){ x=read();y=read(); z=lca(x,y); if(z==s){ query(y,s);mi=dis[y]-mi; ans=dis[x]+(mi>0?0:mi); query(x,s);mi=dis[x]-mi; ans=min(ans,dis[y]+(mi>0?0:mi)); printf("%d ",ans); } else if(z==x){ query(y,x);mi=dis[y]-mi; printf("%d ",mi>0?0:mi); } else if(z==y){ query(x,y);mi=dis[x]-mi; printf("%d ",mi>0?0:mi); } else { query(y,z);mi=dis[y]-mi; ans=dis[x]+(mi>0?0:mi)-dis[z]; query(x,z);mi=dis[x]-mi; ans=min(ans,dis[y]+(mi>0?0:mi)-dis[z]); printf("%d ",ans); } } return 0; }