題目大意:
給一顆基環樹,求所有長度大於等於K的路徑。
題目分析:
如果沒有環,只有樹的話,只要裸上樹分治就可以了。
有環的話我們就先把環上的一條邊去掉,然後做樹分治。
這樣我們就統計出了所有不經過這條邊的路徑樹,還剩下所有經過這條邊的路徑數。
我們此時處理出以環上所有點位根的子樹信息,並將其合併。
然後每次去掉環上一個點的信息,再用這個點的子樹信息與環上其他點的子樹信息更新答案(通過剛纔刪掉那條邊的)。
代碼如下:
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define N 120000
using namespace std;
typedef long long LL;
inline int lowbit(int x) { return x&-x; }
int n,m,K,sum,root,rtf;
int fir[N],nes[N<<1],v[N<<1],tot=1;
int fw[N],tim[N],fa[N],son[N],sz[N],sta[N],top;
int Time_Stamp,Cut;
bool mark[N],vis[N];
vector<int> ring;
LL ans;
void edge(int x,int y)
{
v[++tot]=y;
nes[tot]=fir[x];
fir[x]=tot;
return;
}
#define edge(x,y) edge(x,y),edge(y,x)
void update(int x,int v=1)
{
for(;x;x-=lowbit(x))
{
if(tim[x]!=Time_Stamp)
tim[x]=Time_Stamp,fw[x]=0;
fw[x]+=v;
}
return;
}
int query(int x)
{
int ans=0;
if(x<=0) x=1;
for(;x<=n;x+=lowbit(x))
{
if(tim[x]!=Time_Stamp)
tim[x]=Time_Stamp,fw[x]=0;
ans+=fw[x];
}
return ans;
}
void DFS(int c)
{
mark[c]=true;
for(int t=fir[c];t;t=nes[t])
{
if(v[t]==fa[c] || t==Cut || t==(Cut^1)) continue;
if(mark[v[t]])
{
int tmp=c;
while(tmp!=v[t])
{
ring.push_back(tmp);
tmp=fa[tmp];
}
ring.push_back(tmp);
Cut=t;
continue;
}
fa[v[t]]=c;
DFS(v[t]);
}
}
void find_focus(int c,int fa)
{
sz[c]=1; son[c]=0;
for(int t=fir[c];t;t=nes[t])
{
if(v[t]==fa || t==Cut || t==(Cut^1) || vis[v[t]]) continue;
find_focus(v[t],c);
sz[c]+=sz[v[t]];
if(sz[v[t]]>son[c]) son[c]=sz[v[t]];
}
if(sum-sz[c]>son[c]) son[c]=sum-sz[c];
if(son[c]<=son[root]) root=c,rtf=fa;
}
void dfs(int c,int fa,int dep)
{
sta[++top]=dep;
for(int t=fir[c];t;t=nes[t])
{
if(v[t]==fa || vis[v[t]] || t==Cut || t==(Cut^1)) continue;
dfs(v[t],c,dep+1);
}
}
void solve(int c)
{
vis[c]=true;
Time_Stamp++;
update(1);
for(int t=fir[c];t;t=nes[t])
{
if(vis[v[t]] || t==Cut || t==(Cut^1)) continue;
top=0;
dfs(v[t],0,1);
for(int i=1;i<=top;i++) ans+=query(K-sta[i]);
for(int i=1;i<=top;i++) update(sta[i]+1);
}
for(int t=fir[c];t;t=nes[t])
{
if(vis[v[t]] || t==Cut || t==(Cut^1)) continue;
root=0; sum=sz[v[t]];
find_focus(v[t],0);
solve(root);
sz[rtf]=sum-sz[root];
}
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
edge(x,y);
}
DFS(1);
son[0]=sum=n; root=0;
find_focus(1,0);
sz[rtf]=sum-sz[root];
solve(root);
sum=ring.size();
memset(vis,0,sizeof(vis));
for(int i=0;i<sum;i++) vis[ring[i]]=true;
Time_Stamp++;
for(int i=0;i<sum;i++)
{
top=0;
dfs(ring[i],0,1);
for(int j=1;j<=top;j++)
update(sta[j]+i);
}
for(int i=sum-1;i>=0;i--)
{
top=0;
dfs(ring[i],0,1);
for(int j=1;j<=top;j++)
update(sta[j]+i,-1);
for(int j=1;j<=top;j++)
ans+=query(K-sta[j]-sum+i+1);
}
printf("%lld\n",ans);
return 0;
}