求环套外向树上节点数不小于K的路径数。

首先树的话直接点分治+树状数组$O(n\log^2n)$搞定

环套树的话,先删掉多余的边(a,b)

然后变成了一棵树,直接点分治

然后在树上找到a到b的路径,将每一棵子树中的点的“所有权”(要么从a出发到达,要么从b出发到达)改变一下,然后计算贡献即可。

总时间复杂度$O(n\log^2n+n\log n)$

把BZOJ第700题献给了这道题…

#include<cstdio>
#define N 100010
typedef long long ll;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,m,K,i,x,y,g[N],nxt[N<<1],v[N<<1],ok[N<<1],ed=1,son[N],f[N],size,now,fa[N],exa,exb,to[N],way[N],cnt,in[N],dis[N],t[N],pos;
ll ans,bit[N];
inline void addedge(int x,int y){v[++ed]=y,nxt[ed]=g[x],ok[ed]=1,g[x]=ed;}
int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
inline void add(int x){for(;x<=n;x+=x&-x)if(t[x]!=pos)t[x]=pos,bit[x]=1;else bit[x]++;}
inline void del(int x){for(;x<=n;x+=x&-x)bit[x]--;}
inline ll sum(int x){if(x<0)return 0;ll y=0;for(;x;x-=x&-x)if(t[x]==pos)y+=bit[x];return y;}
void findroot(int x,int pre){
son[x]=1;f[x]=0;
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre){
findroot(v[i],x);
son[x]+=son[v[i]];
if(son[v[i]]>f[x])f[x]=son[v[i]];
}
if(size-son[x]>f[x])f[x]=size-son[x];
if(f[x]<f[now])now=x;
}
void dfscal(int x,int pre,int dep){
ans+=sum(n)-sum(K-dep-1);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfscal(v[i],x,dep+1);
}
void dfsadd(int x,int pre,int dep){
add(dep+1);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfsadd(v[i],x,dep+1);
}
void solve(int x){
int i;
pos++,add(1);
for(i=g[x];i;i=nxt[i])if(ok[i])dfscal(v[i],x,1),dfsadd(v[i],x,1);
for(i=g[x];i;i=nxt[i])if(ok[i])ok[i^1]=0,f[0]=size=son[v[i]],findroot(v[i],now=0),solve(now);
}
void path(int x,int pre,int d){
to[x]=pre,add(dis[x]=d);
for(int i=g[x];i;i=nxt[i])if(v[i]!=pre)path(v[i],x,d+1);
}
void treecal(int x,int pre,int d){
ans+=sum(n)-sum(K-d-1);
for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&!in[v[i]])treecal(v[i],x,d+1);
}
void treedel(int x,int pre){
del(dis[x]);
for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&!in[v[i]])treedel(v[i],x);
}
int main(){
read(n),read(m),read(K);
for(i=1;i<=n;i++)fa[i]=i;
while(m--){
read(x),read(y);
if(F(x)==F(y))exa=x,exb=y;else fa[fa[x]]=fa[y],addedge(x,y),addedge(y,x);
}
f[0]=size=n,findroot(1,now=0),solve(now);
if(exa){
pos++,path(exa,0,1);
for(i=exb;i;i=to[i])in[way[++cnt]=i]=1;
for(i=1;i<cnt;i++)treedel(way[i],0),treecal(way[i],0,i);
}
return printf("%lld",ans),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】寝室管理 树分治

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

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

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

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

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

  6. BZOJ3648:寝室管理

    浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem. ...

  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. 配置oss bucket cors

    到bucket中属性中选择跨越设置,点击添加规则会看到以下界面: 对应的输入如上即可.

  2. 算法:comparable比较器的排序原理实现(二叉树中序排序)

    Comparable比较器排序远离实现 package test.java.api.api13; /** * 手工实现二叉树的比较算法: 第一遍感觉很神秘,但是真正自己写下来,就感觉很简单,理解就好: ...

  3. Android studio 添加依赖

    以前添加依赖总是到github上下载源码,再添加源码到module的依赖当中,其实在studio中,应该使用maven库. 比如在github上看到了sliding-menu这个项目,就应该到mave ...

  4. DFS:Red and Black(POJ 1979)

    红与黑 题目大意:一个人在一个矩形的房子里,可以走黑色区域,不可以走红色区域,从某一个点出发,他最多能走到多少个房间? 不多说,DFS深搜即可,水题 注意一下不要把行和列搞错就好了,我就是那样弄错过一 ...

  5. codeforces A. The Wall 解题报告

    题目链接:http://codeforces.com/problemset/problem/340/A 这道题目理解不难,就是在[a, b]区间内,找出同时能够被x和y整除的个数.第一次想当然的开了两 ...

  6. Codeforces7C 扩展欧几里得

    Line Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Submit Status ...

  7. Android中如何让手机屏幕不待机

    在Android中,申请WakeLock可以让你的进程持续执行即使手机进入睡眠模式,比较实用的是比如后台有网络功能,可以保证操作持续进行. 方法: 在操作之前加入 PowerManager pm = ...

  8. C++ 提取字符串中的数字

    C++ 提取字符串中的数字 #include <iostream> using namespace std; int main() { ] = "1ab2cd3ef45g&quo ...

  9. 简单dp的状态转移方程集合

    1.对于任一种N的排列A,定义它的E值为序列中满足A[i]>i的数的个数.给定N和K(K<=N<=1000),问N的排列中E值为K的个数. dp[i][j]表示i个数的排列中E值为j ...

  10. JavaBeans、EJB和POJO详解

    转自:http://developer.51cto.com/art/200906/130814.htm J2EE学习者越来越多,J2EE本身技术不断在发展,涌现出各种概念,本文章试图从一种轻易理解的角 ...