话说这个题号怎么这么的诡异…
Description
Solution
用点分治,统计过重心的路径个数
对于重心,以它为根,全局做一遍DFS序,
对于非重心的点x,枚举它的倍数y,有3种情况:
1. y在x到根的路径上:直接退出;
2. y在x的子树中:在y打上标记,做到y时直接退出
3. y在其他地方:y和y子树中的点都无法到达x和x的子树,x和x子树中的点都无法到达y和y的子树;
每个点的值最开始默认为1,也就是合法,
发现上面的操作只有子树赋值,所以用DFS即可
细节在这里就不一一细讲了
复杂度:O(nlog(n)2)
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
using namespace std;
typedef long long LL;
const int N=1005000;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
LL ans;
int B[2*N][2],A[N],B0;
int B1[50*N][3],A1[N],B10;
struct qwqw
{
int si,zx,TI1;
}a[N];
int b0,TI1;
struct qqww
{
int la,s;
int l,r,g;
}b[N*55];
int root[N];
bool z[N];
int z1[N],TI;
void link(int q,int w)
{
B[++B0][0]=A[q];A[q]=B0,B[B0][1]=w;
B[++B0][0]=A[w];A[w]=B0,B[B0][1]=q;
}
void CK(int &e,int g){if(b[e].g!=g)b[++b0]=b[e],b[e=b0].g=g;}
void doit(int l,int r,int e)
{
if(b[e].la==-1)return;
b[e].s=b[e].la*(r-l+1);
if(l!=r)CK(b[e].l,b[e].g),CK(b[e].r,b[e].g),b[b[e].l].la=b[b[e].r].la=b[e].la;
b[e].la=-1;
}
void build(int l,int r,int &e,int g)
{
e=++b0;b[e]=b[0];
b[e].g=g;b[e].la=-1;
if(l==r)
{
b[e].s=1+(l==1);
return;
}
int t=(l+r)>>1;
build(l,t,b[e].l,g);
build(t+1,r,b[e].r,g);
b[e].s=b[b[e].l].s+b[b[e].r].s;
}
void change(int l,int r,int &e,int g,int l1,int r1,int l2)
{
if(l1>r1)return;
CK(e,g);
int t=(l+r)>>1;
doit(l,t,b[e].l),doit(t+1,r,b[e].r);
if(l==l1&&r==r1)
{
b[e].la=l2;
doit(l,r,e);
return;
}
if(r1<=t)change(l,t,b[e].l,g,l1,r1,l2);
else if(t<l1)change(t+1,r,b[e].r,g,l1,r1,l2);
else
{
change(l,t,b[e].l,g,l1,t,l2);
change(t+1,r,b[e].r,g,t+1,r1,l2);
}
b[e].s=b[b[e].l].s+b[b[e].r].s;
}
int find_all(int root)
{
doit(1,n,root);
return b[root].s;
}
int D,Ds;
int dfsf(int q,int fa,int all)
{
a[q].zx=++b0;a[q].si=1;a[q].TI1=TI1;
A1[q]=0;root[q]=0;
int mx=0;
efo(i,q)if(B[i][1]!=fa&&!z[B[i][1]])a[q].si+=dfsf(B[i][1],q,all),mx=max(mx,a[B[i][1]].si);
mx=max(mx,all-a[q].si);
if(mx<Ds)Ds=mx,D=q;
return a[q].si;
}
void link1(int q,int l,int r)
{
B1[++B10][0]=A1[q];A1[q]=B10,B1[B10][1]=l;B1[B10][2]=r;
}
void dfs1(int q,int fa,int all,int Q)
{
if(z1[q]==1e9+TI)
change(1,all,root[Q],Q,a[q].zx,a[q].zx+a[q].si-1,0);
z1[q]=TI;
fo(i,2,n/q)if(a[q*i].TI1==TI1)
{
if(z1[q*i]==TI)change(1,all,root[Q],Q,a[q].zx,a[q].zx+a[q].si-1,0);
else if(a[q*i].zx<a[q].zx||a[q*i].zx>=a[q].zx+a[q].si)
{
link1(q*i,a[q].zx,a[q].zx+a[q].si-1);
}else z1[i*q]=1e9+TI;
}
efo(i,q)if(B[i][1]!=fa&&!z[B[i][1]])dfs1(B[i][1],q,all,Q);
z1[q]=0;
}
void dfs(int q,int fa,int all)
{
if(z1[q]==1e9+TI)
{
z1[q]=0;return;
}
z1[q]=TI;if(!root[q])root[q]=root[fa];
for(int i=A1[q];i;i=B1[i][0])
change(1,all,root[q],q,B1[i][1],B1[i][2],0);
fo(i,2,n/q)if(a[q*i].TI1==TI1)
{
if(z1[q*i]==TI)return;
if(a[q*i].zx<a[q].zx||a[q*i].zx>=a[q].zx+a[q].si)
{
change(1,all,root[q],q,a[q*i].zx,a[q*i].zx+a[q*i].si-1,0);
}else z1[i*q]=1e9+TI;
}
ans+=(LL)find_all(root[q]);
efo(i,q)if(B[i][1]!=fa&&!z[B[i][1]])dfs(B[i][1],q,all);
z1[q]=0;
}
void divide(int q,int all)
{
if(all<2)return;
Ds=D=1e9;dfsf(q,0,all);
q=D;z[q]=1;TI1++;
B10=b0=0;
dfsf(q,0,all);
b0=root[q]=0;
build(1,all,root[q],q);
efo(i,q)if(!z[B[i][1]])
{
TI++;
dfs1(B[i][1],q,all,q);
}
fo(i,2,n/q)if(a[i*q].TI1==TI1)link1(i*q,1,all);
fo(j,2,n/q)if(a[j*q].TI1==TI1)
change(1,all,root[q],q,a[j*q].zx,a[j*q].zx+a[j*q].si-1,0);
for(int j=A1[q];j;j=B1[j][0])
change(1,all,root[q],q,B1[j][1],B1[j][2],0);
int b0t=b0;
if(q!=1)
efo(i,q)if(!z[B[i][1]])
{
root[B[i][1]]=root[q];b0=b0t;
change(1,all,root[B[i][1]],B[i][1],a[B[i][1]].zx,a[B[i][1]].zx+a[B[i][1]].si-1,0);
TI++;
z1[q]=TI;
dfs(B[i][1],q,all);
}
efo(i,q)if(!z[B[i][1]])divide(B[i][1],a[B[i][1]].si);
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int q,w;
read(n);
fo(i,1,n-1)read(q),read(w),link(q,w);
divide(1,n);
printf("%d\n",ans/2);
return 0;
}