点分治
点分治算法解决很多树上路径问题。
代码下面提供了几组Hack。
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int n,m,sum;
int vis[10005];
int size[10005];
vector<vector<pair<int,int>>> a;
int dfs1(int u,int fa) {
size[u]=1;
for(auto&i:a[u]) {
int v=i.first;
if(v==fa||vis[v]) continue;
size[u]+=dfs1(v,u);
}
return size[u];
}
int f[10005],temp;
void dfs2(int u,int fa) {
f[u]=sum-size[u];
for(auto&i:a[u]) {
int v=i.first;
if(v==fa||vis[v]) continue;
dfs2(v,u);
f[u]=max(f[u],size[v]);
}
}
void dfs3(int u,int fa) {
for(auto&i:a[u]) {
int v=i.first;
if(v==fa||vis[v]) continue;
dfs3(v,u);
}
if(f[temp]>f[u]) temp=u;
}
int getroot(int u) {
sum=dfs1(u,0);//初始化size
temp=u;
dfs2(u,0);//初始化f
dfs3(u,0);//选取temp
return temp;
}
int que[1005];
int t[10000005],stp/*时间戳*/;
int queue[10005],top;
void dfs4(int u,int fa,int val) {
queue[++top]=val;
for(auto&i:a[u]) {
int v=i.first,p=i.second;
if(vis[v]||v==fa) continue;
dfs4(v,u,val+p);
}
}
void div(int u) {
vis[u]=true;
t[0]=++stp;
for(auto&i:a[u]) {
int v=i.first,p=i.second;
if(vis[v]) continue;
dfs4(v,u,p);
for(int j=1; j<=top; j++) {
int val=queue[j];
for(int i=1; i<=m; i++)
if(~que[i]&&que[i]-val>=0&&que[i]-val<=10000000&&t[que[i]-val]==stp)
que[i]=-1;
}
for(int j=1; j<=top; j++)
if(queue[j]<=10000000)
t[queue[j]]=stp;
top=0;
}
}
void calc(int u) {
int root=getroot(u);
div(root);
for(auto&i:a[root]) {
int v=i.first;
if(vis[v]) continue;
calc(v);
}
}
int main() {
f[0]=1e9;
cin>>n>>m;
for(int i=0; i<=n; i++) a.push_back({});
for(int i=1; i<n; i++) {
int u,v,w;
cin>>u>>v>>w;
a[u].push_back({v,w});
a[v].push_back({u,w});
}
for(int i=1; i<=m; i++) cin>>que[i];
calc(1);
for(int i=1; i<=m; i++)
if(~que[i])
cout<<"NAY"<<endl;
else
cout<<"AYE"<<endl;
return 0;
}
/*
5 20
1 2 1
1 3 2
2 4 4
3 5 8
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
NAY
4 5
1 2 1
2 3 2
1 4 1
1 2 3 4 5
AYE
AYE
AYE
AYE
NAY
3 5
1 2 1
1 3 2
1 2 3 4 5
AYE
AYE
AYE
NAY
NAY
2 5
1 2 2
1 2 3 4 5
NAY
AYE
NAY
NAY
NAY
*/
- 注意每一递归处都要判vis和fa
- 注意不能把dfs3的最后一句话合并到dfs2函数的末尾,因为此时temp=u,而f[u]还没有被更新。
- 注意有关于queue的值域限制,防止爆桶,但是同时也要注意,大于107的值只是不应放在桶里,而不是不做判断了,因为有可能减去q[i]之后满足条件
一道板题
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<vector<pair<int,int>>> a;
int n;
long long ans;
int size[20005],f[20005],sum,temp;
bool vis[20005];
int dfs1(int u,int fa) {
size[u]=1;
for(auto&i:a[u]) {
int v=i.first;
if(vis[v]||v==fa) continue;
size[u]+=dfs1(v,u);
}
return size[u];
}
int dfs2(int u,int fa) {
f[u]=sum-size[u];
for(auto&i:a[u]) {
int v=i.first;
if(vis[v]||v==fa) continue;
f[u]=max(f[u],dfs2(v,u));
}
return size[u];
}
void dfs3(int u,int fa) {
for(auto&i:a[u]) {
int v=i.first;
if(vis[v]||v==fa) continue;
dfs3(v,u);
}
if(f[temp]>f[u]) temp=u;
}
int getroot(int u) {
sum=dfs1(u,0);
temp=u;
dfs2(u,0);
dfs3(u,0);
return temp;
}
long long t[3],queue[3];
void dfs4(int u,int fa,int val) {
queue[val%3]++;
for(auto&i:a[u]) {
int v=i.first,p=i.second;
if(v==fa||vis[v]) continue;
dfs4(v,u,val+p);
}
}
void div(int u) {
vis[u]=true;
t[0]=1;
for(auto&i:a[u]) {
int v=i.first,p=i.second;
if(vis[v]) continue;
dfs4(v,u,p);
for(int k=0;k<3;k++) ans+=(queue[k]*t[(3-k)%3])<<1;
for(int k=0;k<3;k++) t[k]+=queue[k];
for(int k=0;k<3;k++) queue[k]=0;
}
for(int k=0;k<3;k++)
t[k]=0;
}
void calc(int u) {
int root=getroot(u);
div(root);
for(auto&i:a[root]) {
int v=i.first;
if(vis[v]) continue;
calc(v);
}
}
int main(){
cin>>n;
for(int i=0;i<=n;i++) a.push_back({});
for(int i=1;i<n;i++) {
int u,v,w;
cin>>u>>v>>w;
a[u].push_back({v,w});
a[v].push_back({u,w});
}
calc(1);
ans+=n;
long long x=(long long)n*n;
long long g=__gcd(ans,x);
cout<<ans/g<<'/'<<x/g;
return 0;
}
/*
3
1 2 1
1 3 2
2
*/
没什么细节
后记
于是皆大欢喜。