Description
r 64 有一个好朋友,叫r 128 。r 128 是寄宿生,并且最近被老师叫过去当宿管了。宿
管可不是一件很好做的工作,碰巧r 128 有一个工作上的问题想请r 64 帮忙解决。
r 128 的寝室条件不是很好,所以没有很多钱来装修。n间寝室仅由n − 1条双向道
路连接,而且任意两间寝室之间都可以互达。最近,r 128 被要求对一条路径上的所有
寝室进行管理, 这条路径不会重复经过某个点或某条边。 但他不记得是哪条路径了。
他只记得这条路径上有不少于k个寝室。于是,他想请r 64 帮忙数一下,有多少条这
样的路径满足条件。
嗯…还有一个问题。由于最近有一些熊孩子不准晚上讲话很不爽,他们决定修筑
一条“情报通道”,如果通道建成,寝室就变成了一个n个点n条边的无向图。并且,
经过“情报通道”的路径也是合法的。r 128 心想:通道建成之前,r 64 还有一个高效
的算法帮我数路径条数,但是通道建成之后,他还有办法吗?对,r 64 手忙脚乱,根
本数不清有多少条路径。于是他找到了你。
Input
输入第一行为三个正整数n, m, k(2 ≤ k ≤ n),代表有n间寝室,
m条边连接它们(n − 1 ≤ m ≤ n;m = n − 1意味着“情报通道”未被修好;m = n意
味着“情报通道”已被修好),以及题目描述中的k。
接下来m行,每行两个正整数x, y,代表第x间寝室与第y间寝室之间有一条双向
边。
Output
输出仅包含一个整数,代表经过至少k间寝室的路径条数。
Sample Input
5 5 2
1 3
2 4
3 5
4 1
5 2
Sample Output
20
Data Constraint
Solution
对于树:点分治(模板)
对于环套树:
首先找到环上一条边切掉,变成树,统计答案
然后没统计到的必定经过这条边
沿着一个方向扫描整个环,对于当前扫描到的一个点,统计它的子树到被切掉那条边其中一个端点的距离与数据结构中的哪一段长度拼起来,然后再把这个子树中到那条边另一个端点的距离加入数据结构,统计就行了
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
#define INF 214748347
#define cl(a) memset(a,0,sizeof(a))
#define ll long long
#define lowbit(a) ((a)&(-a))
using namespace std;
int n,m,k,last[N],next[N*2],to[N*2],tot=1,bz[N],root,size[N],ts,a[N],mx[N],deep[N],s[N],c[N],flag=0,t[N*10];
ll ans;
void putin(int x,int y)
{
next[++tot]=last[x];last[x]=tot;to[tot]=y;
}
void groot(int x,int fat)
{
mx[x]=0;
size[x]=1;
for(int i=last[x];i;i=next[i])
if(i!=flag&&i!=(flag^1))
{
int y=to[i];if(y==fat||bz[y]) continue;
groot(y,x);size[x]+=size[y];
mx[x]=max(mx[x],size[y]);
}
mx[x]=max(mx[x],ts-size[x]);
if(mx[x]<mx[root]) root=x;
}
void gdeep(int x,int fat)
{
for(int i=last[x];i;i=next[i])
if(i!=flag&&i!=(flag^1))
{
int y=to[i];if(y==fat||bz[y]) continue;
deep[y]=deep[x]+1;gdeep(y,x);
}
a[++tot]=deep[x];
}
ll calc()
{
ll ans=0,i=1,j=tot;
sort(a+1,a+tot+1);
while(i<j)
{
if(a[i]+a[j]-1>=k) ans+=j-i,j--;
else i++;
}
return ans;
}
void dg(int x,int fat)
{
bz[x]=1;deep[x]=1;
tot=0;gdeep(x,fat);
ans+=calc();
for(int i=last[x];i;i=next[i])
if(i!=flag&&i!=(flag^1))
{
int y=to[i];if(bz[y]) continue;
tot=0;deep[y]=2;gdeep(y,x);
ans-=calc();
ts=size[y];root=0;groot(y,x);
dg(root,x);
}
}
void findc(int x,int fat)
{
s[++s[0]]=x;bz[x]=1;
for(int i=last[x];i;i=next[i])
if(i!=fat)
{
if(flag) return;
int y=to[i];
if(bz[y])
{
for(;s[s[0]+1]!=y;s[0]--) c[++c[0]]=s[s[0]];
flag=i;
return;
}
findc(y,i^1);
}
s[0]--;
}
void ins(int x)
{
for(;x<=n;x+=lowbit(x)) t[x]++;
}
ll get(int x)
{
ll jy=0;
for(;x;x-=lowbit(x)) jy+=t[x];
return jy;
}
void dfs(int qq,int x,int fat,int d)
{
if(qq==1) ans+=get(n)-get(max(k-d-1,0));
else ins(d);
for(int i=last[x];i;i=next[i])
{
int y=to[i];if(y==fat||s[y]) continue;
dfs(qq,y,x,d+1);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
fo(i,1,m)
{
int x,y;scanf("%d%d",&x,&y);
putin(x,y);putin(y,x);
}
if(m==n-1)
{
mx[0]=INF;root=0;ts=n;groot(1,0);
dg(root,0);
printf("%lld\n",ans);
}
else
{
findc(1,0);cl(bz);
mx[0]=INF;root=0;ts=n;groot(1,0);
dg(root,0);
int jy=0;cl(s);
fo(i,1,c[0]) s[c[i]]=1;
fo(i,1,c[0])
{
dfs(1,c[i],0,c[0]-jy);
jy++;
dfs(2,c[i],0,jy);
}
printf("%lld\n",ans);
}
}