您的位置:首页 > 其它

JZOJ5385. 【NOIP2017提高A组模拟9.23】Carry 树上倍增

2017-09-23 15:58 555 查看
题意:给你一棵树,q对点,要求每次从qx走到qy的花费为最大路径权值,可以把一条边减小L,问最少花费。

= =简单题,比赛的时候只是扫了一眼,觉得应该是树剖裸题,然后就放了= =

事实上也可以用树剖来做,但是非常复杂,难以维护。

倍增就好了,和那个次小生成树一样,维护一个每个点往上2^i的路径的最大次大权值。然后那个L的那个东西,我每次在求一对点的LCA过程中,直接用已经求出的最大次大维护,然后最后把最大边拉出来记录一下,最后把所有边扫一遍+不改边的贡献就ok。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
const int inf=2e9;
typedef long long ll;
int n,m,q,l;
int fa
[22],head
,next
,go
,val
;
int dep
;
ll ans,sum
;
int mx
[22],mx2
[22];
int id
[22],tot;
inline void add(int x,int y,int z)
{
go[++tot]=y;
next[tot]=head[x];
val[tot]=z;
head[x]=tot;
}
inline void dfs(int x,int last,int y)
{
fa[x][0]=last,mx[x][0]=y;
id[x][0]=x;
dep[x]=dep[last]+1;
fo(i,1,19)
{
fa[x][i]=fa[fa[x][i-1]][i-1];
if (mx[x][i-1]>mx[fa[x][i-1]][i-1])
{
mx[x][i]=mx[x][i-1];
id[x][i]=id[x][i-1];
mx2[x][i]=max(mx2[x][i-1],mx[fa[x][i-1]][i-1]);
}
else
{
int fat=fa[x][i-1];
mx[x][i]=mx[fat][i-1];
id[x][i]=id[fat][i-1];
mx2[x][i]=max(mx2[fat][i-1],mx[x][i-1]);
}
}
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=last)
dfs(v,x,val[i]);
}
}
inline void update(int x,int i,int& Mx,int& Mx2,int& Id)
{
if (mx[x][i]>Mx)
{
Mx2=max(Mx2,max(Mx,mx2[x][i]));
Mx=mx[x][i];
Id=id[x][i];
}
else Mx2=max(Mx2,mx[x][i]);
}
inline void mark(int mx,int mx2,int id)
{
ans+=mx;
if (mx2==mx)return;
sum[id]+=(mx-mx2<=l)?mx2-mx:-l;
}
inline void solve(int x,int y)
{
if (x==y)return ;
int mx=-inf,mx2=-inf,id=0;
if (dep[x]<dep[y])swap(x,y);
if (dep[x]>dep[y])
fd(i,19,0)if (dep[fa[x][i]]>=dep[y])
{
update(x,i,mx,mx2,id);
x=fa[x][i];
}
if (x==y)
{
mark(mx,mx2,id);
return;
}
fd(i,19,0)
{
if (fa[x][i]!=fa[y][i])
{
update(x,i,mx,mx2,id);
update(y,i,mx,mx2,id);
x=fa[x][i],y=fa[y][i];
}
}
update(x,0,mx,mx2,id);
update(y,0,mx,mx2,id);
mark(mx,mx2,id);
}
int main()
{
//freopen("carry.in","r",stdin);
//freopen("carry.out","w",stdout);
scanf("%d%d%d",&n,&q,&l);
fo(i,1,n-1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dfs(1,0,0);
fo(i,1,q)
{
int x,y;
scanf("%d%d",&x,&y);
solve(x,y);
}
ll mn=1e15;
fo(i,1,n)mn=min(mn,sum[i]);
printf("%lld\n",ans+mn);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: