3648: 寝室管理

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 239  Solved: 106
[Submit][Status][Discuss]

Description

T64有一个好朋友,叫T128。T128是寄宿生,并且最近被老师叫过去当宿管了。宿管可不是一件很好做的工作,碰巧T128有一个工作上的问题想请T64帮忙解决。
  T128的寝室条件不是很好,所以没有很多钱来装修。礼间寝室仅由n-1条双向道路连接,而且任意两间寝室之间都可以互达。最近,T128被要求对一条路径上的所有寝室进行管理,这条路径不会重复经过某个点或某条边。但他不记得是哪条路径了。他只记得这条路径上有不少于k个寝室。于是,他想请T64帮忙数一下,有多少条这样的路径满足条件。
    嗯…还有一个问题。由于最近有一些熊孩子不准晚上讲话很不爽,他们决定修筑一条“情报通道”,如果通道建成,寝室就变成了一个N个点N条边的无向图。并且,经过“情报通道”的路径也是合法的。T128心想:通道建成之前,T64还有一个高效的算法帮我数路径条数,但是通道建成之后,他还有办法吗?对,T64手忙脚乱,根本数不清有多少条路径。于是他找到了你。

Input

第一行为三个正整数N,M,K(2 ≤ K ≤ N),代表有n间寝室,m条边连接它们n-1 ≤ m ≤ N;m= n-1意味着“情报遁道”未被修好;m=n意味着“情报通道”已被修好),以及题目描述中的K。
  接下来m行,每行两个正整数z,y,代表第x间寝室与第y间寝室之间有一条双向边。

Output

仅包含一个整数,代表经过至少K间寝室的路径条数。

Sample Input

5 5
1 3
2 4
3 5
4 1
5 2

Sample Output

20

HINT

N≤100000      
K≤N
M=N

Source

Solution

首先考虑M=N-1的情况,路径问题,树上可以直接点分治算出

M=N的情况,就是环套树,方法是一样的,先拆环,用处理树的方法计算答案,然后单独计算经过环的答案

找环的过程,并查集即可....

统计答案,利用树状数组即可,或者Splay,线段树都可以,具体作用就是处理完一颗子树,将答案加入树状数组,再处理其他子树的时候,再加入答案进行计算,保证不出现遗漏

考虑经过环的情况,从路径上找到环,更新环上点的所有权,再进行一次计算,即可

或者,正反扫两次环亦可

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
void Freopen() {freopen("sport.in","r",stdin); freopen("sport.out","w",stdout);}
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
int N,M,K;
struct EdgeNode{int next,to;}edge[MAXN<<];
int head[MAXN],cnt=;
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
int CA,CB,f[MAXN],visit[MAXN],mark[MAXN],size[MAXN],deep[MAXN],Size,root,from[MAXN],C[MAXN],cn;
long long Ans;
struct BinaryIndexedTree
{
int NUM,bl[MAXN],id;
long long tree[MAXN];
int lowbit(int x) {return x&(-x);}
void Add(int pos,int D)
{
for (int i=pos; i<=NUM; i+=lowbit(i))
if (bl[i]!=id)
tree[i]=,bl[i]=id;
else
tree[i]+=D;
}
void Sub(int pos,int D)
{
for (int i=pos; i<=NUM; i+=lowbit(i))
tree[i]+=D;
}
long long Query(int pos)
{
if (pos<) return ;
long long re=;
for (int i=pos; i; i-=lowbit(i))
if (bl[i]==id) re+=tree[i];
return re;
}
long long Query(int L,int R) {return Query(R)-Query(L-);}
}bit;
struct UnionFind
{
int Fa[MAXN];
void init() {for (int i=; i<=N; i++) Fa[i]=i;}
int find(int x) {if (Fa[x]==x) return x; else return Fa[x]=find(Fa[x]);}
void merge(int x,int y) {int f1=find(x),f2=find(y); if (f1!=f2) Fa[f1]=f2;}
}uf;
void DFSroot(int now,int last)
{
f[now]=,size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
{
DFSroot(edge[i].to,now);
size[now]+=size[edge[i].to];
f[now]=max(f[now],size[edge[i].to]);
}
f[now]=max(f[now],Size-size[now]);
if (f[now]<f[root]) root=now;
}
void CalcT(int now,int last,int dep)
{
Ans+=bit.Query(K-dep,N);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
CalcT(edge[i].to,now,dep+);
}
void AddAns(int now,int last,int dep)
{
bit.Add(dep+,);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
AddAns(edge[i].to,now,dep+);
}
void Divide(int now)
{
visit[now]=;
bit.id++; bit.Add(,);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
CalcT(edge[i].to,now,),AddAns(edge[i].to,now,);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
{
f[root=]=Size=size[edge[i].to];
DFSroot(edge[i].to,now);
Divide(root);
}
}
void SolveT()
{
f[root=]=N; Size=N;
DFSroot(,);
Divide(root);
}
void GetCircle(int now,int last,int dep)
{
from[now]=last; bit.Add(dep,); deep[now]=dep;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
GetCircle(edge[i].to,now,dep+);
}
void CalcCT(int now,int last,int D)
{
Ans+=bit.Query(K-D,N);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !mark[edge[i].to])
CalcCT(edge[i].to,now,D+);
}
void SubAns(int now,int last)
{
bit.Sub(deep[now],-);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !mark[edge[i].to])
SubAns(edge[i].to,now);
}
void SolveCT()
{
bit.id++; GetCircle(CA,,);
for (int i=CB; i; i=from[i]) C[++cn]=i,mark[i]=;
for (int i=; i<cn; i++) SubAns(C[i],),CalcCT(C[i],,i);
}
int main()
{
// Freopen();
N=read(); M=N; M=read(); K=read();
uf.init(); bit.NUM=N;
for (int x,y,i=; i<=M; i++)
{
x=read(),y=read();
if (uf.find(x)!=uf.find(y)) InsertEdge(x,y),uf.merge(x,y); else CA=x,CB=y;
}
SolveT();
if (N==M) SolveCT();
printf("%lld\n",Ans);
return ;
}

这里有个坑,某种大环的情况,会被卡RE....

【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治的更多相关文章

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

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

  2. BZOJ 3648 寝室管理

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

  3. 5.15 牛客挑战赛40 E 小V和gcd树 树链剖分 主席树 树状数组 根号分治

    LINK:小V和gcd树 时限是8s 所以当时好多nq的暴力都能跑过. 考虑每次询问暴力 跳父亲 这样是nq的 4e8左右 随便过. 不过每次跳到某个点的时候需要得到边权 如果直接暴力gcd的话 nq ...

  4. 2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组,CDQ分治

    TMD...这题卡内存卡的真优秀... 所以以后还是别用主席树的写法...不然怎么死的都不知道... 树套树中,主席树方法开权值线段树...会造成空间的浪费...这道题内存卡的很紧... 由于树套树已 ...

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

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

  6. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

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

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

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

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

  9. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

随机推荐

  1. JDK7中的新特性 The try-with-resources Statement

    https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html 类似于这样的代码 try ( By ...

  2. DEDECMS之三 首页、列表页怎么调用文章内容

    一.首页调用 百度了很多,没有找到实际的解决方法,对于直接读取数据库,这种写法不会采取. 后来,仔细考虑,这部分解决的内容不会很多,所以直接使用了简介的内容 方法一(默认长度55) [field:in ...

  3. 快速判断素数 --Rabin-Miller算法

    以前我在判断素数上一直只会 sqrt(n) 复杂度的方法和所谓的试除法(预处理出sqrt(n)以内的素数,再用它们来除). (当然筛选法对于判断一个数是否是素数复杂度太高) 现在我发现其实还有一种方法 ...

  4. 微软职位内部推荐-B&I Site Lead

    微软近期Open的职位: Job Title: B&I Site Lead Division: Phones Quality, SWIQ Location: Beijing, China Mi ...

  5. 分布式消息系统:Kafka

    Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为Apache项目的一部分.Kafka是一个分布式的,可划分的,冗余备份的持久性的日志服务.它主要用于处理活跃的流式数据. ...

  6. mac 10.9.4下配置apache

    mac 10.9.x已经自带了apache,可按如下步骤开启: 1.启动 sudo apachectl start 启动后,访问 http://localhost/ 应该能看到"It wor ...

  7. JAVA格物致知开篇:凡事预则立不预则废

    在我的这一生中,我发现我做事的方式可以用一句话概括:凡事预则立,不预则废.这么多年,我一直秉承着要做有准备的事情,不打无准备之仗的道理来过活.其实这样会让我的妻子非常的烦恼,她是乐天派,喜欢事情来了才 ...

  8. 虾皮工作室QQ群列表

    各位博友: 本群不仅仅是提供好的资料,更重要是提供平台,提供解决问题的方法和思路.求人不如求己,掌握合理的方法和方式才是不断进步的根本.看我的文档,不单单是看内容,更应该从整理的方式和角度是深思,去想 ...

  9. C# 值类型和引用类型

    一.基本概念 C#只有两种数据类型:值类型和引用类型 值类型在线程栈分配空间,引用类型在托管堆分配空间 值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱 以下是值类型和引用类型对照表 从上图可 ...

  10. 7z压缩文件时排除指定的文件

    分享一个7z压缩文件时排除指定文件类型的命令行,感觉很有用: 7z a -t7z d:\updateCRM.7z d:\updateCRM\*.* -r -x!*.log -x!*bak a:创建压缩 ...