浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3648

基环树分治,结合了点分和边分的思想。

先随便拆掉环上一条边,我们先称它为基边,把它当做树做一遍,跟Free Tour II差不多。

剩下的问题就是如何统计经过基边的路径条数了。我们将基边连着的两个点分别成为\(st\)和\(ed\),\(st\)的顺时针方向是\(ed\),\(ed\)的逆时针方向是\(st\)。直接跟边分一样去分别处理\(st\)和\(ed\)能延伸出去的路径长度不行,因为这样会在环上产生交集然后统计不合法的路径。所以我们枚举基边以外的边去断开再统计答案,就可以保证统计出来的答案不重不漏了。

然后因为只要做一遍,所以大力树状数组也没关系。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
#define low(i) ((i)&(-(i))) const int maxn=1e5+5; ll ans;
bool vis[maxn],bo;
int n,m,limit,tot=1,id,mx,rt,N;
int now[maxn],pre[maxn*2],son[maxn*2];
int siz[maxn],f[maxn],g[maxn],depest[maxn],V[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} void add(int a,int b) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b;
} struct TreeArray {
int c[maxn]; void change(int pos,int v) {
if(pos==n-13)mx++;
for(int i=pos;i<=n;i+=low(i))
c[i]+=v;
} int query(int pos) {
int res=0;
for(int i=pos;i;i-=low(i))
res+=c[i];
return res;
}
}T; struct ring {
int node1,node2;
int dis[maxn],nxt[maxn],lst[maxn]; bool find_ring(int fa,int u) {
vis[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(v!=fa) {
if(vis[v])id=p>>1,node1=v,node2=u;
if(vis[v]||find_ring(u,v)) {
nxt[u]=v,lst[v]=u;
return 1;
}
}
return 0;
} void dfs(int fa,int u,int num) {
if(num==1)dis[u]=dis[fa]+1;
T.change(n-dis[u]+1,num);
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)dfs(u,v,num);
} void query(int fa,int u) {
dis[u]=dis[fa]+1,ans+=T.query(n-(max(1,limit-dis[u]))+1);
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)query(u,v);
} void work() {
lst[node1]=node2;
memset(vis,0,sizeof(vis));
int st=son[id<<1],ed=son[id<<1|1];
if(nxt[st]==ed)swap(st,ed);
int pos=st;vis[ed]=1;
while(pos!=ed)vis[pos]=1,pos=nxt[pos];
dis[ed]=0,pos=st;mx=0;
while(pos!=ed)dfs(lst[pos],pos,1),pos=nxt[pos];dfs(lst[ed],ed,1);
pos=ed;dis[st]=0;
while(pos!=st)dfs(nxt[pos],pos,-1),query(nxt[pos],pos),pos=lst[pos];
}
}R; void find_rt(int fa,int u) {
int res=0;siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&(p>>1)!=id&&v!=fa)
find_rt(u,v),siz[u]+=siz[v],res=max(res,siz[v]);
res=max(res,N-siz[u]);
if(res<mx)mx=res,rt=u;
} void dfs(int fa,int u,int dep) {
mx=max(mx,dep),siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&(p>>1)!=id&&v!=fa)
dfs(u,v,dep+1),siz[u]+=siz[v];
} bool cmp(int a,int b) {
return depest[a]<depest[b];
} void query(int fa,int u,int dep) {
ans+=f[max(1,limit-dep)];
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa&&(p>>1)!=id)query(u,v,dep+1);
} void solve(int fa,int u,int dep) {
g[dep]++;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa&&(p>>1)!=id)solve(u,v,dep+1);
} void work(int u,int size) {
N=size,mx=rt=n+1,find_rt(0,u),u=rt,vis[u]=1,tot=0;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&(p>>1)!=id) {
V[++tot]=v,mx=0;
dfs(u,v,2),depest[v]=mx;
}
sort(V+1,V+tot+1,cmp);
for(int i=1;i<=tot;i++) {
query(u,V[i],1);
solve(u,V[i],2);
for(int j=depest[V[i]];j;j--)
g[j]+=g[j+1],f[j]+=g[j];
for(int j=1;j<=depest[V[i]];j++)g[j]=0;
}
ans+=f[limit];
for(int i=1;i<=depest[V[tot]];i++)f[i]=g[i]=0;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&(p>>1)!=id)work(v,siz[v]);
} int main() {
n=read(),m=read(),limit=read();
for(int i=1;i<=m;i++) {
int a=read(),b=read();
add(a,b),add(b,a);
}
if(m==n)R.find_ring(0,1);
memset(vis,0,sizeof(vis));
work(1,n);
if(m==n)R.work();
printf("%lld\n",ans);
return 0;
}

最新文章

  1. 6.bootstrap练习笔记-缩略图和list-group
  2. Anyconnect的VPN环境部署(1)-OpenConnect server(ocserv)服务安装
  3. Git删除tag
  4. mysql错误用法insert into where
  5. vi 命令行模式功能键
  6. 关于mybatis用mysql时,插入返回自增主键的问题
  7. 二维码URL自己主动辨别Android和ISO设备,以便扫码后倒入不同的下载链接
  8. 【解决ViewPager在大屏上滑动不流畅】 设置ViewPager滑动翻页距离
  9. GO中的数组切片
  10. Android 6.0 双向通话自动录音
  11. Java基础学习笔记二十一 多线程
  12. Powershell Linux正式版可用,启动名称有变
  13. 笔记:stm32 printf重定向到UART疑点解析
  14. CommonJS 规范中的 module、module.exports 区别
  15. [C基础修炼]如何用vs2017写一个C语言hello world程序
  16. 关于C# WinForm中进度条的实现方法
  17. java Field 二三事
  18. Visual Studio 开始支持编写 Android 程序并自带 Android 模拟器【转载】
  19. java.lang.ClassNotFoundException: org.apache.commons.beanutils.DynaBean
  20. sublime text3 破解及常用插件

热门文章

  1. ubantu 下 修改mysql 默认编码
  2. 结缘mac
  3. 巧用Excel提高工作效率
  4. TP 框架 如果去掉表前缀
  5. pjax简单实例
  6. python 基础 6.1 异常处理方法
  7. windowsphone8.1学习笔记之应用数据(一)
  8. Hadoop实战-Flume之Source multiplexing(十五)
  9. 【题解】Fence(单调队列)
  10. X86汇编 BT