题目链接
说实话一开始这个题目题解我是完全没看懂的
哪怕我把天天不爱跑步做完了也一样…..
还是对题目理解的不太清楚啊
首先把对于任意一条路径
s−>t
s
−
>
t
,我们可以把它拆成
s−>lca(s,t)
s
−
>
l
c
a
(
s
,
t
)
和
lca(s,t)−>t
l
c
a
(
s
,
t
)
−
>
t
然后处理就会比较方便了
之前做谈笑风生这个题的时候也用过一个这样的思想。
如果某个点子树内某种深度的点对答案有贡献。
那么可以把每个深度的信息存下来,相当于开个桶。
入栈的时候减去全局这个深度的信息,出栈的时候加回来就好了
联系一下 dfs d f s 相关的东西应该不是很难理解
这道题我们也可以这样子 对于向上的路径
如果 x x 对有贡献 那么一定满足 dep[x]=dep[i]+w[i] d e p [ x ] = d e p [ i ] + w [ i ]
就每次遍历到起点就 cnt[dep[x]] c n t [ d e p [ x ] ] 加 1 1 就好了
到出栈的时候再减掉就好了
算答案的时候算的就是 cnt[dep[i]+w[i]] c n t [ d e p [ i ] + w [ i ] ] 的值
向下的路径可以同样考虑
如果 x x 对有贡献 那么一定满足 dep[i]−dep[lca]=w[i]−(dep[x]−dep[lca]) d e p [ i ] − d e p [ l c a ] = w [ i ] − ( d e p [ x ] − d e p [ l c a ] )
意义就是 lca l c a 到 i i 所花的时间与出现观察员的时间减去路径上已经花费的时间
移项可得 dep[lca]×2−dep[x]=dep[i]−w[i] d e p [ l c a ] × 2 − d e p [ x ] = d e p [ i ] − w [ i ]
由于这次我们统计的是 lca l c a 到 y y 之间的路径,所以也是在上减回来
在 y y 加就好了 算答案算的时候是的值
这个下标可能是负的 用 std::map s t d :: m a p 类似的东西就可以解决了
复杂度 O(nlogn) O ( n l o g n )
Codes
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#define pb push_back
using namespace std;
__gnu_pbds::gp_hash_table<int, int> cnt1, cnt2;
const int N = 6e5 + 10;
vector<int> G[N], ins1[N], del1[N], ins2[N], del2[N];
int dep[N], fa[N][21];
int w[N], ans[N];
int n, m;
void dfs(int x) {
for(auto v : G[x])
if(!dep[v]) {
dep[v] = dep[x] + 1;
fa[v][0] = x;
dfs(v);
}
}
int lca(int x, int y) {
if(dep[x] != dep[y]) {
if(dep[x] < dep[y]) swap(x, y);
for(int j = 20; ~ j; -- j)
if(dep[fa[x][j]] > dep[y])
x = fa[x][j];
x = fa[x][0];
}
if(x == y) return x;
for(int j = 20; ~ j; -- j)
if(fa[x][j] != fa[y][j])
x = fa[x][j], y = fa[y][j];
return fa[x][0];
}
void dfs1(int u, int dad) {
ans[u] -= cnt1[dep[u] + w[u]];
for(auto i : ins1[u]) {
++ cnt1[i];
// cout << "ADD " << u << ' ' << i << endl;
}
for(auto v : G[u])
if(v != dad)
dfs1(v, u);
//if(u == 1) cout << ans[1] << endl;
ans[u] += cnt1[dep[u] + w[u]];
//if(u == 1) cout << dep[u] + w[u] << ' ' << ans[1] << endl;
for(auto i : del1[u]) {
-- cnt1[i];
//cout << "DEL " << u << ' ' << i << endl;
}
//if(u == 2) cout << ans[2] << endl;
}
void dfs2(int u, int dad) {
ans[u] -= cnt2[dep[u] - w[u]];
for(auto i : ins2[u]) {
++ cnt2[i];
// cout << "ADD " << u << ' ' << i << endl;
}
for(auto v : G[u])
if(v != dad)
dfs2(v, u);
ans[u] += cnt2[dep[u] - w[u]];
for(auto i : del2[u]) {
-- cnt2[i];
// cout << "DEL " << u << ' ' << i << endl;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("2359.in", "r", stdin);
freopen("2359.out", "w", stdout);
#endif
int x, y, z;
scanf("%d%d", &n, &m);
for(int i = 1; i < n; ++ i) {
scanf("%d%d", &x, &y);
G[x].pb(y), G[y].pb(x);
}
for(int i = 1; i <= n; ++ i)
scanf("%d", &w[i]);
dfs(dep[1] = 1);
for(int j = 1; j <= 20; ++ j)
for(int i = 1; i <= n; ++ i)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
for(int i = 1; i <= m; ++ i) {
scanf("%d%d", &x, &y);
int f = lca(x, y); z = dep[x] - dep[f];
ins1[x].pb(dep[x]); del1[f].pb(dep[x]);
ins2[y].pb(dep[f] - z); del2[f].pb(dep[f] - z);
//cout << f << ' ' << y << endl;
if(dep[f] + w[f] == dep[x]) -- ans[f];
}
dfs1(1, 0), dfs2(1, 0);
for(int i = 1; i <= n; ++ i)
printf("%d ", ans[i]);
return 0;
}
感觉自己主要毛病就是没太看懂题就开题了 以后还是不要太毛躁 老老实实看完
再根据自己会做的分来分配时间