186. [USACO Oct08] 牧场旅行
★★☆ 输入文件:pwalk.in
输出文件:pwalk.out
逐字节对比
时间限制:1 s 内存限制:128 MB
n个被自然地编号为1..n奶牛(1<=n<=1000)正在同样被方便的编号为1..n的n个牧场中吃草。更加自然而方便的是,第i个奶牛就在第i个牧场中吃草。
其中的一些对牧场被总共的n-1条双向通道的一条连接。奶牛可以通过通道。第i条通道连接的两个牧场是A_i和B_i(1<=A_i<=N;1<=B_i<=N)其长度是L_i(1<=L_i<=10000)。
通道只会连接两个不同的牧场,所以这些通道使得整个牧场构成了一棵树。
奶牛们是好交际的希望能够经常的访问别的奶牛。急切地,它们希望你能通过告诉它们Q(1<=Q<=1000)对牧场的路径来帮助他们安排旅行。(这里将有Q个询问,p1,p2(1<=p1<=n;1<=p1<=n))
分数:200
问题名称:pwalk
输入格式:
- 第1行:两个用空格隔开的整数:n和Q
- 第2..n行:第i+1行包含三个用空格隔开的整数:A_i,B_i和L_i
- 第n+1..N+Q行:每行包含两个用空格隔开的整数,代表两个不同的牧场,p1和p2
输入样例(file pwalk.in):
4 2 2 1 2 4 3 2 1 4 3 1 2 3 2
输出格式:
- 第1..Q行:行i包含第i个询问的答案。
输出样例:
2 7
输出说明:
询问1:牧场1和牧场2的路径长度为2。 询问2:3->4->1->2;总长为7。
就是一个树链剖分求LCA
#include<bits/stdc++.h> #define maxn 1005 using namespace std; int N,Q; vector<int> v[maxn],w[maxn]; int dis[maxn]; int size[maxn],dep[maxn],fa[maxn],son[maxn],pos[maxn],dfn[maxn]; int cnt,top[maxn]; void Dfs(int x) { size[x]=1; for(int i=0;i<v[x].size();i++) { int y=v[x][i]; if(!size[y]) { fa[y]=x; dep[y]=dep[x]+1; dis[y]=dis[x]+w[x][i]; Dfs(y); size[x]+=size[y]; if(size[y]>size[son[x]]) son[x]=y;//更新重儿子 } } } void Dfs(int x,int Tp) { top[x]=Tp; dfn[++cnt]=x; pos[x]=cnt; if(son[x]) { Dfs(son[x],Tp);//先走重链 } for(int i=0;i<v[x].size();i++) { int to=v[x][i]; if(!top[to]) { Dfs(to,to);//轻链 } } } int LCA(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); return x; } int main() { // freopen("pwalk.in","r",stdin); // freopen("pwalk.out","w",stdout); scanf("%d%d",&N,&Q); for(int i=2;i<=N;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); v[x].push_back(y); w[x].push_back(z); v[y].push_back(x); w[y].push_back(z); } Dfs(1);Dfs(1,1); for(int i=1;i<=Q;i++){ int x,y; scanf("%d%d",&x,&y); printf("%d ",dis[x]+dis[y]-2*dis[LCA(x,y)]); } return 0; }