题目:BZOJ3648.
题目大意:给定一棵
n
n
n个点的树或基环树,求这棵树上点个数超过
k
k
k的路径数量.
1
≤
n
≤
1
0
5
1\leq n\leq10^5
1≤n≤105.
如果这道题是树的话,这就是个点分治模板.
考虑基环树的情况.首先把环找出来,去掉环上一条边得到一棵树,对这棵树进行点分治得到一个答案,最终答案就是点分治出来的答案加上强制选择环上那条边边时基环树上点个数超过 k k k的路径数量.
考虑把经过环上某条边 ( x , y ) (x,y) (x,y)的路径 ( u , v ) (u,v) (u,v)拆成 ( u , x ) (u,x) (u,x)和 ( y , v ) (y,v) (y,v)两段计算贡献,此时我们发现可以枚举 v v v对应在环上的祖先,用一个树状数组维护 u u u那一段的贡献即可.
时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
int n,m,sk;
struct side{
int y,next,tag;
}e[N*2+9];
int lin[N+9],cs;
void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}
int ca,a[N+9],vis[3][N+9];
int Dfs_a(int k){
vis[0][k]=1;a[++ca]=k;
for (int i=lin[k];i;i=e[i].next)
if (!vis[0][e[i].y]) Dfs_a(e[i].y);
}
queue<int>q;
int deg[N+9];
void Topsort(){
for (int i=1;i<=ca;++i)
if (deg[a[i]]==1) q.push(a[i]);
while (!q.empty()){
int t=q.front();q.pop();
vis[1][t]=1;
for (int i=lin[t];i;i=e[i].next)
if (--deg[e[i].y]==1) q.push(e[i].y);
}
}
int rng[N+9],cr,tag[N+9];
bool Get_rng(){
cr=0;
for (int i=1;i<=ca;++i)
if (!vis[1][a[i]]) {rng[cr=1]=a[i];break;}
if (!cr) return 0;
while (2333){
int flag=0;
tag[rng[cr]]=vis[1][rng[cr]]=1;
for (int i=lin[rng[cr]];i;i=e[i].next)
if (!vis[1][e[i].y]) {rng[++cr]=e[i].y;flag=1;break;}
if (!flag) break;
}
return 1;
}
int siz[N+9],g[N+9];
int Dfs_siz(int k,int fa){
siz[k]=1;g[k]=0;
for (int i=lin[k];i;i=e[i].next)
if (!vis[2][e[i].y]&&e[i].y^fa&&!e[i].tag){
Dfs_siz(e[i].y,k);
siz[k]+=siz[e[i].y];
g[k]=max(g[k],siz[e[i].y]);
}
}
int Dfs_heart(int k,int fa,int rot){
g[k]=max(g[k],siz[rot]-siz[k]);
int res=k,t;
for (int i=lin[k];i;i=e[i].next)
if (!vis[2][e[i].y]&&e[i].y^fa&&!e[i].tag){
t=Dfs_heart(e[i].y,k,rot);
if (g[t]<g[res]) res=t;
}
return res;
}
int Get_heart(int k){Dfs_siz(k,0);return Dfs_heart(k,0,k);}
LL c[N+9];
void Add(int p,LL v){for (;p<=n;p+=p&-p) c[p]+=v;}
LL Query(int p){LL res=0;for (p=p<0?0:p;p;p-=p&-p) res+=c[p];return res;}
LL Query(int L,int R){return Query(R)-Query(L-1);}
LL Dfs_calc(int k,int fa,int t,int flag){
LL res=Query(sk-t,n);
for (int i=lin[k];i;i=e[i].next)
if (!(flag&&vis[2][e[i].y])&&e[i].y^fa&&!e[i].tag&&(flag||!tag[e[i].y]))
res+=Dfs_calc(e[i].y,k,t+1,flag);
return res;
}
void Dfs_ins(int k,int fa,int t,int flag){
Add(t,1);
for (int i=lin[k];i;i=e[i].next)
if (!(flag&&vis[2][e[i].y])&&e[i].y^fa&&!e[i].tag&&(flag||!tag[e[i].y]))
Dfs_ins(e[i].y,k,t+1,flag);
}
void Dfs_del(int k,int fa,int t,int flag){
Add(t,-1);
for (int i=lin[k];i;i=e[i].next)
if (!(flag&&vis[2][e[i].y])&&e[i].y^fa&&!e[i].tag&&(flag||!tag[e[i].y]))
Dfs_del(e[i].y,k,t+1,flag);
}
LL Calc(int k){
LL res=0;
Add(1,1);
for (int i=lin[k];i;i=e[i].next)
if (!vis[2][e[i].y]&&!e[i].tag){
res+=Dfs_calc(e[i].y,k,1,1);
Dfs_ins(e[i].y,k,2,1);
}
Add(1,-1);
for (int i=lin[k];i;i=e[i].next)
if (!vis[2][e[i].y]&&!e[i].tag) Dfs_del(e[i].y,k,2,1);
return res;
}
LL Divide(int k){
vis[2][k=Get_heart(k)]=1;
LL res=Calc(k);
for (int i=lin[k];i;i=e[i].next)
if (!vis[2][e[i].y]&&!e[i].tag) res+=Divide(e[i].y);
return res;
}
LL Solve_rng(){
LL res=0;
for (int i=1;i<=cr;++i) Dfs_ins(rng[i],0,cr-i+1,0);
for (int i=1;i<=cr;++i){
Dfs_del(rng[i],0,cr-i+1,0);
res+=Dfs_calc(rng[i],0,i,0);
}
return res;
}
LL Solve(int st){
ca=0;
Dfs_a(st);
Topsort();
if (!Get_rng()) return Divide(st);
else{
for (int i=lin[rng[1]];i;i=e[i].next)
if (e[i].y==rng[cr]) {e[i].tag=e[i^1].tag=1;break;}
return Divide(st)+Solve_rng();
}
}
LL ans;
Abigail into(){
scanf("%d%d%d",&n,&m,&sk);
cs=1;
for (int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
Ins2(x,y);
++deg[x];++deg[y];
}
}
Abigail work(){
for (int i=1;i<=n;++i)
if (!vis[0][i]) ans+=Solve(i);
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}