树上的数
树上统计类的题目可以尝试往 (dsu) (on) (tree) 方向想。
#include<bits/stdc++.h>
#define IL inline
#define LL long long
#define pb push_back
using namespace std;
const int N=3e5+3;
struct hh{
int to,nxt;
}e[N<<1];
int n,num,fir[N],a[N],vis[N],pri[N],vv[N],b1[N],b2[N],cc[N],c[N];
int dep[N],siz[N],son[N];
LL sum[N],ans;
vector<int>v[N];
IL int in(){
char c;int f=1;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
int x=c-'0';
while((c=getchar())>='0'&&c<='9')
x=x*10+c-'0';
return x*f;
}
IL void ini(int x,int y){e[++num]=(hh){y,fir[x]},fir[x]=num;}
void init(){
for(int i=1;i<N;++i) vv[i]=1,v[i].pb(1);
for(int i=2;i<N;++i)
if(!b1[i]){
v[i].pb(i);
if(!b2[i]) vv[i]=i,cc[i]=1;
for(int j=i+i;j<N;j+=i){
if(!b2[i]) vv[j]*=i;
cc[j]+=!b2[i],v[j].pb(i),b2[j]=1;
}
if(!b2[i]&&i<=2000) for(int j=i*i;j<N;j+=i*i) b1[j]=1;
}
}
void dfs1(int u,int fa){
siz[u]=1,dep[u]=dep[fa]+1;
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa){
dfs1(v,u),siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
IL void add(int u,int op){for(int i=0;i<v[a[u]].size();++i) sum[v[a[u]][i]]+=op*dep[u],c[v[a[u]][i]]+=op;}
IL void Add(int u,int fa,int op){
add(u,op);
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa) Add(v,u,op);
}
void calc(int u,int fa,int x){
for(int i=0;i<v[a[u]].size();++i)
ans+=(cc[v[a[u]][i]]&1?-1:1)*(sum[v[a[u]][i]]+1ll*(dep[u]-2*dep[x])*c[v[a[u]][i]]);
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa) calc(v,u,x);
}
void dfs2(int u,int fa,int op){
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa&&v^son[u]) dfs2(v,u,1);
if(son[u]) dfs2(son[u],u,0);
for(int i=0;i<v[a[u]].size();++i)
ans+=(cc[v[a[u]][i]]&1?-1:1)*(sum[v[a[u]][i]]-1ll*c[v[a[u]][i]]*dep[u]);
add(u,1);
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa&&v^son[u]) calc(v,u,u),Add(v,u,1);
if(op) Add(u,fa,-1);
}
int main()
{
int x,y;
init(),n=in();
for(int i=1;i<=n;++i) a[i]=vv[in()];
for(int i=1;i<n;++i)
x=in(),y=in(),
ini(x,y),ini(y,x);
dfs1(1,0),dfs2(1,0,0);
printf("%lld
",ans);
return 0;
}
树上的树
子树差分,树剖做法有点类似于动态dp。
#include<bits/stdc++.h>
#define IL inline
#define LL long long
#define pb push_back
using namespace std;
const int N=1e6+3;
struct hh{
int to,nxt;
}e[N<<1];
struct kk{
int to,id;
};
int n,m,fir[N],num,fa[N],st[N],ed[N],vis[N];
int X[N],Y[N],w[N];
LL f[N];int val[N];
vector<int>pi[N];
vector<kk>p[N];
struct BIT{
LL c[N];
IL int lb(int x){return x&-x;}
IL void add(int y,LL x){for(;y<=n;y+=lb(y)) c[y]+=x;}
IL LL ask(int y){LL res=0;for(;y;y-=lb(y)) res+=c[y];return res;}
}T;
IL int in(){
char c;int f=1;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
int x=c-'0';
while((c=getchar())>='0'&&c<='9')
x=x*10+c-'0';
return x*f;
}
IL LL max(LL x,LL y){return x>y?x:y;}
IL void add(int x,int y){e[++num]=(hh){y,fir[x]},fir[x]=num;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void dfs1(int u,int fa){
st[u]=++num;
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(v^fa) dfs1(v,u);
ed[u]=num;
}
void dfs2(int u){
LL Sum=0,res=0;vis[u]=1;
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(!vis[v]) dfs2(v),Sum+=f[v],fa[v]=u;
for(int i=0,v;i<p[u].size();++i)
if(vis[v=p[u][i].to]==2) pi[find(v)].pb(p[u][i].id);
T.add(st[u],Sum);
for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
if(vis[v]==2) T.add(st[v],res-f[v]),res=f[v];
T.add(ed[u]+1,res-Sum);
for(int i=0,v;i<pi[u].size();++i){
v=pi[u][i];
f[u]=max(f[u],T.ask(st[X[v]])+T.ask(st[Y[v]])+w[v]-Sum);
}
f[u]=max(f[u],Sum+val[u]);
vis[u]=2;
}
signed main()
{
int x,y,z;
n=in(),m=in();
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<n;++i)
x=in(),y=in(),
add(x,y),add(y,x);
num=0,dfs1(1,0);
for(int i=1;i<=m;++i){
X[i]=in(),Y[i]=in(),w[i]=in();
if(X[i]==Y[i]) val[X[i]]=max(val[X[i]],w[i]);
else p[X[i]].pb((kk){Y[i],i}),p[Y[i]].pb((kk){X[i],i});
}
dfs2(1);
printf("%lld
",f[1]);
return 0;
}