分析:
mmp,终于找到这道题了
考试的时候想到了bzoj1060,就在blog中找了好久,终于链接上了
虽然这两道题没有什么直接关联,但是有题目描述有一些相同的地方,可以放在一起对比一下
一开始看到这道题,竟然脑抽到用线性规划单纯型解决
我大概石乐志。。。
废话不多说,开始正解吧
先说一下50%的部分:
设开始所有边权的集合为S,那必然存在一种最优解,使得调整过后的所有边权也在S集合中
时间复杂度
O(n2)
O
(
n
2
)
100%
不妨尝试用函数表示状态
ai
a
i
:表示i号结点到父结点的边权
fi,j
f
i
,
j
:表示以i为根的子树已经处理完毕,末端权值均不小于j的最小代价
gi,j
g
i
,
j
:表示以i为根的子树已经处理完毕,且i结点到父亲的边的取值为j的最小代价
hi,j
h
i
,
j
:表示以i为根的子树已经处理完毕,且i结点到父亲的边取值不小于j的最小代价
转移方程:
fi,j=∑hson,j
f
i
,
j
=
∑
h
s
o
n
,
j
gi,j=fi,j+|ai−j|
g
i
,
j
=
f
i
,
j
+
|
a
i
−
j
|
hi,j=min(hi,j+1,gi,j)
h
i
,
j
=
m
i
n
(
h
i
,
j
+
1
,
g
i
,
j
)
可以发现:
- 函数均为下凸壳
- 斜率均为整数
- 需要支持操作叠加两个函数(斜率对应相加)
- 求后缀最小值(将负斜率清零)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int INF=1<<31;
const int N=200005;
int n,m,st[N],tot,top,q[N],fa[N],a[N],f[N];
ll s[N];
struct node{
int y,nxt,v;
};
node way[N<<1];
struct Tree{
int lc,rc,dis,data;
};
Tree t[N<<1];
void add(int u,int w,int z)
{
tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
tot++;way[tot].y=u;way[tot].v=z;way[tot].nxt=st[w];st[w]=tot;
}
int new_node(int x)
{
t[++top]=(Tree){0,0,1,x};
return top;
}
int merge(int x,int y)
{
if (!x) return y;
if (!y) return x;
if (t[x].data>t[y].data) swap(x,y);
t[x].rc=merge(t[x].rc,y);
if (t[t[x].lc].dis<t[t[x].rc].dis) swap(t[x].lc,t[x].rc);
t[x].dis=t[t[x].rc].dis+1;
return x;
}
void bfs()
{
int tou,wei;
tou=wei=1;
q[1]=1; fa[1]=1;
a[1]=0; //到父结点的边权
while (tou<=wei)
{
int now=q[tou++];
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa[now])
{
fa[way[i].y]=now;
q[++wei]=way[i].y;
a[way[i].y]=way[i].v;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
memset(st,0,sizeof(st)); tot=0; top=0;
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
add(u,w,z);
}
bfs();
for (int i=n;i>=1;i--) //从叶子开始
{
int now=q[i];
f[now]=0; s[now]=0;
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa[now])
{
f[now]=merge(f[now],f[way[i].y]);
s[now]+=s[way[i].y];
}
f[now]=merge(f[now],merge(new_node(a[now]),new_node(a[now])));
s[now]=(ll)s[now]+a[now]-t[f[now]].data;
f[now]=merge(t[f[now]].lc,t[f[now]].rc);
}
printf("%lld\n",s[1]);
}
return 0;
}