2019-2020 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)
文章目录
A Radio Prize
大意:
求出一颗树上每个点到其他点的距离的和,两个点之间的距离定义为两个点的权值和乘上路径权值和
思路:
明显是换根DP,不过写的时候写了好久…
将所求拆成两个数:这个点的权值乘路径权值和+目标点的权值乘路径权值和,这样就可以维护了,换根的时候求出父节点到这个节点的贡献即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
#define int LL
int n, a[N], sumv[N];
int SUMW = 0;
int sumV[N];
vector<pair<int, int>> mp[N];
int dp[N], dis[N][2], sz[N];
int res[N];
void dfs1(int now, int fa) {
sumv[now] = a[now];
sz[now] = 1;
for (int i = 0; i < mp[now].size(); i++) {
int ne = mp[now][i].first, w = mp[now][i].second;
if (ne == fa) continue;
dfs1(ne, now);
sz[now] += sz[ne]; //子节点数量
dp[now] += dp[ne] + w * sumv[ne]; //子节点的贡献
sumv[now] += sumv[ne]; //子节点权值和
dis[now][0] += dis[ne][0] + w * sz[ne]; //子节点距离和
}
}
void dfs2(int now, int fa) {
for (int i = 0; i < mp[now].size(); i++) {
int ne = mp[now][i].first, w = mp[now][i].second;
if (ne == fa) continue;
dis[ne][1] = dis[now][1] - w * sz[ne] + w * (n - sz[ne]);
res[ne] = dp[ne] + dis[ne][1] * a[ne] + res[now] -
dis[now][1] * a[now] - (dp[ne] + w * sumv[ne]) +
w * (SUMW - sumv[ne]);
dfs2(ne, now);
}
}
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i],SUMW += a[i];
for (int i = 1; i <= n - 1; i++) {
int x, y, w;
cin >> x >> y >> w;
mp[x].push_back({
y, w}), mp[y].push_back({
x, w});
}
dfs1(1, 0);
res[1] = dp[1] + dis[1][0] * a[1];
dis[1][1] = dis[1][0];
dfs2(1, 0);
for (int i = 1; i <= n; i++) cout << res[i] << endl;
return 0;
}
B Perfect Flush
大意:
给出n个数,n个数都是由1到k的数组成,现在要从里面找到一个字典序最小的1到k的全排列
思路:
用栈去维护,如果当前栈顶的数字在后面还会出现,且比当前要入栈的数字大,那么就弹栈
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
int n, k;
int a[MAXN];
int pos[MAXN];
stack<int> sta;
int vis[MAXN];
vector<int> ans;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
pos[a[i]] = i;
}
for (int i = 1; i <= n; i++) {
if (vis[a[i]])<