题解:P15831 [JOI Open 2015] 选举活动 / Election Campaign
AnotherDream · · 题解
一道并不困难的树链剖分。
思路
我们设
一种是不选,就是
还有一种就是选两端点 LCA 为
这样直接转移是
我们设
直接树链剖分做完了。
:::success[代码]
#include <bits/stdc++.h>
using namespace std;
#define debug cerr<<"The code runs successfully.\n";
#define endl '\n'
#define TRACE 1
#define tcout TRACE && cout
#define fst ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define int long long
#define fir first
#define sec second
const int P = 998244353;
const int Base = 33331;
#ifdef int
const int INF = 0x3f3f3f3f3f3f3f3f;
#else
const int INF = 0x3f3f3f3f;
#endif
const int N = 1e5 + 10, M = 1e6 + 10;
int n,dp[N],sum[N],siz[N],m,dfn[N],son[N],top[N],idx,dep[N],fa[N];
vector<int> g[N];
vector<pair<pair<int,int>,int>> chain[N];
struct FenwickTree {//树状数组
int tr[N];
inline void add(int x,int k) {
for(;x<=n;x+=x&-x) tr[x]+=k;
}
inline int ask(int x) {
int res=0;
for(;x;x-=x&-x) res+=tr[x];
return res;
}
inline int ask(int l,int r) {
return ask(r)-ask(l-1);
}
} tr1,tr2;//tr1维护f tr2维护g
void dfs1(int u,int f) {
siz[u]=1,fa[u]=f,dep[u]=dep[f]+1;
for(int v:g[u]) {
if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int f) {
dfn[u]=++idx,top[u]=f;
if(son[u]) dfs2(son[u],f);
for(int v:g[u]) {
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
inline int lca(int u,int v) {//树剖LCA
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
return u;
}
inline void add(int u,int k) {
tr1.add(dfn[u],k);
if(fa[u]) tr2.add(dfn[fa[u]],k);
}
inline int ask1(int u,int v) {//查询链上和
int res=0;
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res+=tr1.ask(dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
res+=tr1.ask(dfn[u],dfn[v]);
return res;
}
inline int ask2(int u,int v) {
int res=0;
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res+=tr2.ask(dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
res+=tr2.ask(dfn[u],dfn[v]);
return res;
}
void solve(int u) {
for(int v:g[u]) {
if(v!=fa[u]) solve(v);
}
int res=ask2(u,u);//不选
for(auto e:chain[u]) {
res=max(res,ask2(e.fir.fir,e.fir.sec)-ask1(e.fir.fir,e.fir.sec)+e.sec);//选
}
add(u,res);
}
signed main() {
// freopen("paths.in","r",stdin);
// freopen("paths.out","w",stdout);
fst;
cin>>n;
for(int i=1;i<n;i++) {
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1,0);
dfs2(1,1);
cin>>m;
for(int i=1;i<=m;i++) {
int u,v,w;
cin>>u>>v>>w;
chain[lca(u,v)].push_back({{u,v},w});
}
solve(1);
cout<<ask1(1,1)<<endl;
return 0;
}
:::