2 条题解
-
0FlameH LV 10 @ 2016-11-08 15:53:30
主要的算法下面两位已经讲得很清楚了 补充一点
就是题目中边权可能为0,如果出现这样的情况会导致算法出错
处理方法是读入的时候先用并查集缩点就好了(然而我**并没有**写这个判断,还是AC了,我猜这个大概是出题人笔误?
```c++
#include <cstdio>
#include <algorithm>
#define N 100050
#define LG 18
#define swap(a,b) std::swap(a,b)
typedef long long ll;
inline int RD()
{
char cr;int res;
while( (cr=getchar())<'0' || cr>'9');
res=cr-'0';
while( (cr=getchar())>='0' && cr<='9')
res=res*10+cr-'0';
return res;
}
inline void PD(ll x)
{
if(!x) return;
PD(x/10);
putc('0'+x%10,stdout);
}
inline void PR(ll x,ll y)
{
x? PD(x): (void)putc('0',stdout);
putc(' ',stdout);
y? PD(y): (void)putc('0',stdout);
putc('\n',stdout);
}
int eg[N<<1],nxt[N<<1],len[N<<1],head[N],egtot;
int fa[N][LG];
ll dis[N][LG];
int h[N];
ll cnt[N],disto[N];
int n;
inline void addEdge(int p1,int p2,int wei)
{
eg[++egtot]=p2;
nxt[egtot]=head[p1];
len[egtot]=wei;
head[p1]=egtot;
}
void dfs(int p)
{
for(int i=1;i<=LG-1;i++)
{
fa[p][i]=fa[fa[p][i-1]][i-1];
dis[p][i]=dis[p][i-1]+dis[fa[p][i-1]][i-1];
}
for(int i=head[p],pt;i;i=nxt[i])
if((pt=eg[i])!=fa[p][0])
{
fa[pt][0]=p;
dis[pt][0]=len[i];
h[pt]=h[p]+1;
disto[pt]=disto[p]+len[i];
dfs(pt);
cnt[p]+=cnt[pt];
}
}
int xlift(int x,int d)
{
for(int i=LG-1;i>=0;i--)
if((1<<i)<=d)
{
d-=1<<i;
x=fa[x][i];
}
return x;
}
int lenlift(int x,ll sumd)
{
for(int i=LG-1;i>=0;i--)
if(sumd>=dis[x][i])
{
sumd-=dis[x][i];
x=fa[x][i];
}
return x;
}
int getlca(int x,int y)
{
bool trans=0;
if(h[x]<h[y]) swap(x,y),trans=1;
x=xlift(x,h[x]-h[y]);
if(x==y) return x;
for(int i=LG-1;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}void solve(int x,int y)
{
if(x==y){PR(0,0);return;}
int lca=getlca(x,y);
ll dx=disto[x]-disto[lca];
ll dy=disto[y]-disto[lca];if(dx==dy)
{
int xson=xlift(x,h[x]-h[lca]-1);
int yson=xlift(y,h[y]-h[lca]-1);
PR(cnt[xson],cnt[yson]);
return;
}
bool trans=0;
ll xans,yans;
if(dx<dy) swap(dx,dy),swap(x,y),trans=1;
int mid=lenlift(x,(dx+dy)/2);
if(disto[x]-disto[mid]==(dx+dy)/2)
{
int xson=xlift(x,h[x]-h[mid]-1);
xans=cnt[xson];
}
else
xans=cnt[mid];
yans=cnt[1]-cnt[mid];
if(trans) swap(xans,yans);
PR(xans,yans);
}
int main()
{
n=RD();
for(int i=1,p1,p2,wei;i<=n-1;i++)
{
p1=RD();p2=RD();wei=RD()*2;//the prog will get WA if wei==0
addEdge(p1,p2,wei);
addEdge(p2,p1,wei);
}
for(int i=1;i<=n;i++)
cnt[i]=RD();
fa[1][0]=1;h[1]=1;
dfs(1);
int Ques=RD();
while(Ques--)
{
int x,y;x=RD();y=RD();
solve(x,y);
}
} -
02015-08-10 16:44:38@
树上倍增写了好久……题解写了好久……
不是不想在这个地方粘,我用word统计了一下题解字数,已经上千字了……
这里看详细题解
- 1