题意:

给你一个有n个点的树,给定根,叫你找第k大的特殊链 。
特殊的链的定义:u,v之间的路径,经过题给的根节点.

题解:(来自BC官方题解)

对于求第k大的问题,我们可以通过在外层套一个二分,将其转化为求不小于mid的有多少个的问题。

接下来我们讨论如何求树上有多少条折链的长度不小于k。

我们考虑常规的点分治(对于重心,求出其到其他点的距离,排序+单调队列),时间复杂度为O(nlog^2n),但是这只能求出普通链的数量。

我们考虑将不属于折链的链容斥掉。也即,我们需要求出有多少条长度不小于mid的链,满足一端是另一端的祖先。设有一条连接u,v的链,u是v的祖先。

我们设d[i]为从根到i的链的长度,然后枚举v,然后计算在从根到v的链上,有多少个点i满足d[v]−dist[i]≥mid

我们可以按照dfs序访问各结点,动态维护从根到其的链上各d值构成的权值树状数组,就能够计算这种链的数量。时间复杂度为O(nlogn)。 因此求长度不小于mid的折链数量可以在O(nlog2​​n)的时间复杂度内完成。再套上最外层的二分,总时间复杂度为O(nlog​3n)。

n的范围是50000,时限6s,卡常数就过去了(本行划线 由于在点分治中,复杂度中第二个logn的瓶颈在于排序。由于每次排序都是对相同的数排序,因此我们可以考虑将点分治+排序作为预处理,每次二分的时候只要做单调队列部分即可。

上述做法的总时间复杂度为O(nlog​2n)。

 #include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=1e5+; int T,n,m,k,g[N],nxt[N],v[N*],w[N*],ed,C[N*],hsh_ed,hsh[*N];
int sz[N],vis[N],mx[N],mi,ROOT,root,idx,ret,cnt;
vector<int>G[N*],G_rt[N]; void adg(int x,int y,int c){v[++ed]=y,w[ed]=c,nxt[ed]=g[x],g[x]=ed;}
inline void up(int &a,int b){if(a<b)a=b;} inline void add(int x,int c){while(x<=hsh_ed)C[x]+=c,x+=x&-x;}
inline int ask(int x){int an=;while(x>)an+=C[x],x-=x&-x;return an;}
inline int getid(int x){return lower_bound(hsh+,hsh++hsh_ed,x)-hsh;} void get_rt(int u,int fa,int num)
{
sz[u]=,mx[u]=;
for(int i=g[u];i;i=nxt[i])
if(v[i]!=fa&&!vis[v[i]])
get_rt(v[i],u,num),sz[u]+=sz[v[i]],up(mx[u],sz[v[i]]);
up(mx[u],num-sz[u]);
if(mx[u]<mi)mi=mx[u],root=u;
} void get_dis(int u,int fa,int dis)
{
G[cnt].push_back(dis);
for(int i=g[u];i;i=nxt[i])
if(v[i]!=fa&&!vis[v[i]])
get_dis(v[i],u,dis+w[i]);
} void init_cal(int u,int dis)
{
cnt++,get_dis(u,u,dis);
sort(G[cnt].begin(),G[cnt].end());
} void get_all(int u)
{
init_cal(u,),vis[u]=;
for(int i=g[u];i;i=nxt[i])
if(!vis[v[i]])
{
init_cal(v[i],w[i]);
mi=sz[v[i]],get_rt(v[i],v[i],sz[v[i]]);
G_rt[u].push_back(root);
get_all(root);
}
} void init_tree()
{
F(i,,n)G_rt[i].clear();
F(i,,*n)G[i].clear();
memset(vis,,sizeof(vis));
mi=n,get_rt(,,n),ROOT=root;
cnt=,get_all(ROOT);
}
//----------------以上为预处理-------- int cal(int mid)
{
int an=;
int i=,j=G[++idx].size()-;
while(i<j)
{
while(j>i&&G[idx][j]+G[idx][i]<mid)i++;
an+=j-i,j--;
}
return an;
} void work(int u,int mid)//求出所有的链
{
ret+=cal(mid),vis[u]=;
int sz=G_rt[u].size()-;
F(i,,sz)ret-=cal(mid),work(G_rt[u][i],mid);
} void dfs(int u,int fa,int dis,int mid)//将每个点过根的距离计算出来
{
hsh[++hsh_ed]=dis,hsh[++hsh_ed]=dis-mid;
for(int i=g[u];i;i=nxt[i])
if(v[i]!=fa)dfs(v[i],u,dis+w[i],mid);
} void get_ret(int u,int fa,int dis,int mid)//容斥不经过根节点的答案
{
int x=getid(dis-mid),y=getid(dis);
ret-=ask(x),add(y,);
for(int i=g[u];i;i=nxt[i])
if(v[i]!=fa)
get_ret(v[i],u,dis+w[i],mid);
add(y,-);
} int check(int mid)
{
ret=,memset(vis,,sizeof(vis));
idx=,work(ROOT,mid);
hsh_ed=,dfs(m,m,,mid);
sort(hsh+,hsh++hsh_ed);
hsh_ed=unique(hsh+,hsh++hsh_ed)-hsh-;
get_ret(m,,,mid);
if(ret>=k)return ;
return ;
} int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
int maxdis=;
memset(g,,sizeof(g)),ed=;
F(i,,n-)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
adg(x,y,c),adg(y,x,c);
up(maxdis,c);
}
init_tree();
int l=,r=maxdis*n,ans=,mid;
while(l<=r)
{
mid=l+r>>;
if(check(mid))ans=mid,l=mid+;
else r=mid-;
}
if(!ans)puts("NO");
else printf("%d\n",ans);
}
return ;
}

hdu 5664 Lady CA and the graph(树的点分治+容斥)的更多相关文章

  1. hdu 5792(树状数组,容斥) World is Exploding

    hdu 5792 要找的无非就是一个上升的仅有两个的序列和一个下降的仅有两个的序列,按照容斥的思想,肯定就是所有的上升的乘以所有的下降的,然后再减去重复的情况. 先用树状数组求出lx[i](在第 i ...

  2. hdu 3682 10 杭州 现场 C To Be an Dream Architect 容斥 难度:0

    C - To Be an Dream Architect Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  3. Luogu4528 CTSC2008 图腾 树状数组、容斥

    传送门 设$f_i$表示$i$排列的数量,其中$x$表示不确定 那么$$ans=f_{1324}-f_{1432}-f_{1243}=(f_{1x2x}-f_{1423})-(f_{14xx}-f_{ ...

  4. bzoj3589 动态树 求链并 容斥

    bzoj3589 动态树 链接 bzoj 思路 求链并. 发现只有最多5条链子,可以容斥. 链交求法:链顶是两条链顶深度大的那个,链底是两个链底的\(lca\) 如果链底深度小于链顶,就说明两条链没有 ...

  5. 【HDU】HDU5664 Lady CA and the graph

    原题链接 题解 距离省选只有一周了我居然才开始数据结构康复计划 这题很简单,就是点分树,然后二分一个值,我们计算有多少条路径大于这个值 对于一个点分树上的重心,我们可以通过双指针的方法求出它子树里的路 ...

  6. HDU 4670 Cube number on a tree ( 树的点分治 )

    题意 : 给你一棵树 . 树的每一个结点都有一个权值 . 问你有多少条路径权值的乘积是一个全然立方数 . 题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数 思路 ...

  7. hdu 5792 World is Exploding 树状数组+离散化+容斥

    World is Exploding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  8. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

  9. HDU 6397(2018多校第8场1001) Character Encoding 容斥

    听了杜教的直播后知道了怎么做,有两种方法,一种构造函数(现在太菜了,听不懂,以后再补),一种容斥原理. 知识补充1:若x1,x2,.....xn均大于等于0,则x1+x2+...+xn=k的方案数是C ...

随机推荐

  1. 【6】锋利的 jQuery 笔记

    1. 代码技巧 1. 利用 id, class 实现同级隐藏显示 效果如下: 2. 字体放大效果 效果图: 3. tab 切换 效果图: 4. 切换样式 添加 Cookie 效果图: 5. 编写插件 ...

  2. JavaEE XML XPath

    JavaEE XML XPath @author ixenos XPath技术 1 引入 问题:当使用dom4j查询比较深的层次结构的节点(标签,属性,文本),比较麻烦!!!需要遍历DOM树的众多节点 ...

  3. C# 动态对象(dynamic)的用法

    说到正确用法,那么首先应该指出一个错误用法: 常有人会拿var这个关键字来和dynamic做比较.实际上,var和dynamic完全是两个概念,根本不应该放在一起做比较.var实际上是编译期抛给我们的 ...

  4. python 数组过滤

    arr = [1,2,3,4,5,6,7,8,None]arr = [elem for elem in arr if elem != None]

  5. 一个App从创意到最终上架到App Store里的整个过程是怎样的?

    一个App从创意到最终上架到App Store里的整个过程是怎样的? 制作App需要什么软件?应该看什么书?需要哪些设备?推到App Store里,需要注册什么网站?是否需要付费?需要什么证书之类的? ...

  6. XML+AJAX

  7. win7安装iis及web配置教程

    下面iis教程只适用win7或win8系统的服务器配置,如果您使用的是xp系统或win2003系统请看:xp或2003安装iis及web配置教程 .注:新手如果嫌iis安装配置麻烦建议下载PageAd ...

  8. MySql 如何实现不同数据库同步【2个】

    环境要求: Windows 操作系统 需要Mysql 3.23.15以后的版本. 假设数据库A为主机,数据库B为从机(A向B提供同步服务,即B中的数据来自A) A机器:IP=10.10.151.166 ...

  9. ListBox 如何改变某行的字体颜色

    Option Explicit Private Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Pri ...

  10. es6语法

    let定义变量,特性: 1,不允许重复定义 2,不存在预解析 3,变量存在于会块级作用域 即{}内部 const : 定义常量,常量的值不能修改,若常量是对象 对象下的属性可修改. 解构赋值语法: 数 ...