浅谈树分治: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;
}

BZOJ3648:寝室管理的更多相关文章

  1. BZOJ3648 寝室管理 【点分治 + 环套树】

    3648: 寝室管理 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 366  Solved: 152 [Submit][Status][Discus ...

  2. bzoj3648: 寝室管理(环套树+点分治)

    好题..写了两个半小时hh,省选的时候要一个半小时内调出这种题目还真是难= = 题目大意是给一棵树或环套树,求点距大于等于K的点对数 这里的树状数组做了一点变换.不是向上更新和向下求和,而是反过来,所 ...

  3. BZOJ3648 : 寝室管理

    求环套外向树上节点数不小于K的路径数. 首先树的话直接点分治+树状数组$O(n\log^2n)$搞定 环套树的话,先删掉多余的边(a,b) 然后变成了一棵树,直接点分治 然后在树上找到a到b的路径,将 ...

  4. 【BZOJ3648】寝室管理 树分治

    [BZOJ3648]寝室管理 Description T64有一个好朋友,叫T128.T128是寄宿生,并且最近被老师叫过去当宿管了.宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T6 ...

  5. 【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治

    3648: 寝室管理 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 239  Solved: 106[Submit][Status][Discuss] ...

  6. BZOJ 3648: 寝室管理( 点分治 + 树状数组 )

    1棵树的话, 点分治+你喜欢的数据结构(树状数组/线段树/平衡树)就可以秒掉, O(N log^2 N). 假如是环套树, 先去掉环上1条边, 然后O(N log^2 N)处理树(同上); 然后再O( ...

  7. BZOJ 3648 寝室管理

    [题解] GDOI2016 Day2T3 如果给出的数据是一棵树那么皆大欢喜直接点分治就好了,用树状数组维护大于x的数的个数.如果是一棵基环树,我们先断掉环上的一条边,然后跑点分治:再加上经过这条边的 ...

  8. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  9. 第五次作业——Alpha项目测试

    第五次作业——Alpha项目测试 格式描述: 这个作业属于哪个课程 2019秋软工17级系统分析与设计 这个作业要求在哪里 作业要求 团队名称 杨荣模杰和他的佶祥虎 这个作业的目标 测试其他组项目并写 ...

随机推荐

  1. JavaOne2013 开发者大会

    参加完JavaOne 2013开发者大会,把听的东西总结一下,基本上是介绍Java的最新发展情况,和对未来的展望. 现在全球有9 million 的Java开发人员,Java语言除了在传统的Enter ...

  2. matlab2016b-linux版本在ubutu16.04x64上面不能打开摄像头的处理方法

    this  can  not  work.    need  find  other way.   ================================================== ...

  3. HTML5 2D平台游戏开发#4状态机

    在实现了<HTML5 2D平台游戏开发——角色动作篇之冲刺>之后,我发现随着角色动作的增加,代码中的逻辑判断越来越多,铺天盖地的if() else()语句实在让我捉襟见肘: 这还仅仅是角色 ...

  4. 【Python + Selenium】初次用IE浏览器之报错:selenium.common.exceptions.WebDriverException: Message: Unexpected error launching Internet Explorer. Protected Mode settings are not the same for all zones.

    初次用IE浏览器运行自动化程序时,报错:selenium.common.exceptions.WebDriverException: Message: Unexpected error launchi ...

  5. Linux下Kafka单机安装配置方法

    Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计.这个独特的设计是什么样的呢? 首先让我们看几个基本的消息系统术语: •Kafka将消息以topi ...

  6. 【Atheros】如何在驱动中禁用ACK

    上一篇文章讲了如何禁用载波侦听(CSMA)和退避(BACKOFF)的方法,这一篇介绍如何禁用ACK. 禁用ACK主要分为三部分: 1. 在发送端设置不等待ACK回来就继续发送: 2. 在接收端设置收到 ...

  7. 【转】php和java之间rsa加密互通

    以下是php封装好的类,引入即可使用 <?php /** * 作者:pjp * 邮箱:vippjp@163.com */ class RSA{ private $privateKey='';// ...

  8. 2015 Astar Contest - Round 3 题解

    1001 数长方形 题目大意 平面内有N条平行于坐标轴的线段,且不会在端点处相交 问共形成多少个矩形 算法思路 枚举4条线段的全部组合.分别作为矩形四条边.推断是否合法 时间复杂度: O(N4) 代码 ...

  9. python 基础及资料汇总

    Python 包.模块.类以及代码文件和目录的一种管理方案     Numpy 小结   用 Python 3 的 async / await 做异步编程  K-means 在 Python 中的实现 ...

  10. MapReduce-PRODUCTION-DEMAND

    [粗暴的HIVE-SQL]select xyz from abc where ty='sdk' and ret_code=0 and data_source_type=1 and dt between ...