素数路径(Prime Distance On Tree )
题意
边长为1,求长度为素数的路径数。
思路
路径计数:点分治+fft
按深度为下标,次数为值卷起来。
结果会吧两端相同的路径算一次,把两端不同的路径算两次。
因此枚举每个点吧对应深度下标减一。
当然这是那种需要容斥的点分治。
code
点击查看代码
#include
using namespace std;
typedef long long ll;
typedef double db;
const db pi=acos(-1);
const int N=1e6+5;
int rev[N],up,l,nxt[N],to[N],head[N],ecnt,n,smx[N],rt;
int p[N],ptot;
bool is_p[N];
ll ans;
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
struct cop {
db img,rl;
friend inline cop operator*(cop x,cop y) {return (cop){x.img*y.rl+x.rl*y.img,x.rl*y.rl-x.img*y.img};}
friend inline cop operator+(cop x,cop y) {return (cop){x.img+y.img,x.rl+y.rl};}
friend inline cop operator-(cop x,cop y) {return (cop){x.img-y.img,x.rl-y.rl};}
}f[N],g[N];
void FFT(cop *a,int op) {
for(int i=0;ii)swap(a[i],a[rev[i]]);
}
for(int mid=1;mid>1]>>1)|((i&1)<<(l-1));
}
bool vis[N];
int sz[N];
void gt_sz(int u,int fa) {
sz[u]=1;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];if(v==fa||vis[v])continue;
gt_sz(v,u);sz[u]+=sz[v];
}
}
void gt_rt(int u,int fa,int tot) {
smx[u]=0;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i]; if(v==fa||vis[v])continue;
gt_rt(v,u,tot);
smx[u]=max(smx[u],sz[v]);
}
smx[u]=max(smx[u],tot-sz[u]);
if(smx[u]