打字
zhongpeilin · · 题解
首先我们类似题意建字典树,设
那么我们发现正着搞不好搞,那么先将答案设为
所以设
那么枚举上一个放入 cache 的单词,假设标号为
你会发现
那么拆一下:
所以:
将一次函数中
CODE:
using namespace std;
#define int long long
struct Segment{
int k, b;
}a[800005];
int tree[800005], tot, ans;
int n, A, B, c[200005], dp[200005], dis[200005];
vector<int> g[200005];
void dfs(int x){
ans += c[x] * A * dis[x];
for(auto it : g[x]){
dis[it] = dis[x] + 1;
dfs(it);
}
}
int GET(int id, int x){
return a[id].k * x + a[id].b;
}
int query(int u, int l, int r, int pos){
if(l == r) return GET(tree[u], l);
int mid = (l + r) / 2;
if(pos <= mid) return max(GET(tree[u], pos), query(u << 1, l, mid, pos));
else return max(GET(tree[u], pos), query(u << 1 | 1, mid + 1, r, pos));
}
void add(int u, int l, int r, int id){
if(!id) return ;
int mid = (l + r) / 2;
if(GET(id, mid) > GET(tree[u], mid) || !tree[u]) swap(id, tree[u]);
if(l == r) return ;
if(GET(id, l) > GET(tree[u], l)) add(u << 1, l, mid, id);
if(GET(id, r) > GET(tree[u], r)) add(u << 1 | 1, mid + 1, r, id);
}
void addedge(int x){
a[++tot] = {-1 * (dis[x] + 1) * A, dp[x]};
add(1, 0, 10000, tot);
}
void DP(int x){
dp[x] = query(1, 0, 10000, c[x]) - B * c[x] + dis[x] * A * c[x];
addedge(x);
cout << dp[x] << endl;
for(auto it : g[x]){
DP(it);
if(dp[it] > dp[x]){
dp[x] = dp[it];
addedge(x);
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> A >> B;
for(int i = 1; i <= n; i++){
int k;
cin >> c[i] >> k;
for(int j = 1; j <= k; j++){
int son;
cin >> son;
g[i].push_back(son);
}
}
dfs(1);
DP(1);
cout << ans - dp[1] << endl;
return 0;
}