题意:

给你一个有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. Selenium WebDriver多层表单切换

    [Java] 首先 测试网站frame结构为 -topframe: -centerframe: -leftframe: -mainframe: -bottomframe: 我当时遇到的问题是,首先在c ...

  2. BGP服务器您了解多少?

    BGP服务器是主要用在不同的自治系统(AS)之间交换路由信息,它的最主要功能在于控制路由的传播和选择最好的路由.比如,中国网通.中国电信.中国铁通和一些大的民营IDC运营商都具有AS号,全国各大网络运 ...

  3. EF CodeFirst使用MySql

    1.引入包 EntityFramework MySql.Data.Entity 2.配置文件 web.config <connectionStrings> <add name=&qu ...

  4. feature2d相关

    1.Harris角点检测 是基于灰度图像的角点检测. 灰度变化率函数如下: 其中的w(x,y)为加权函数,可为常数或为高斯函数.之后对E(u,v)进行泰勒级数的展开与化简,最终得到 ,,Ix,Iy是图 ...

  5. Windows 下 Apache HTTP Server 与 Tomcat 的整合

    整合准备: 1.Apache HTTP Server(下文用Apache简称) 2.Tomcat 7或8 3.mod_jk.so (tomcat-connectors)-这个文件是用来链接http s ...

  6. 必须掌握的Linux命令

    章节简述: 本章节讲述系统内核.Bash解释器的关系与作用,教给读者如何正确的执行Linux命令以及常见排错方法. 经验丰富的运维人员可以恰当的组合命令与参数,使Linux字符命令更加的灵活且相对减少 ...

  7. php注册数模式

    在前两篇单例模式和工厂模式后,终于迎来了最后一个基础的设计模式--注册树模式. 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里矫情一下它的名称,是因为我感觉注册树这个名称更 ...

  8. eclipse 启动tomcat后 页面无法访问tomcat首页

    在eclipse中新建tomcat7,完成后tomcat能够正常启动,但是浏览器问题localhost:8080访问不了. 解决方法如下: 双击eclipse中服务器中的tomcat 出现tomcat ...

  9. WPF 限制Textbox输入的内容

    限制文本框TextBox的输入内容,在很多场景都有应用.举个例子,现在文本框中,只能输入0.1.2.3.4.5.6.7.8.9.“|”这11个字符. 限制输入0-9很容易实现,关键是这个“|”符号.它 ...

  10. 关于PHPAPI ZEND_API TSRM_API宏的定义

    在PHP源码中,我们可以见到诸如PHPAPI ZEND_API TSRM_API等xxx_API(当然还有其他格式的)这样的宏 关于它们的定义都是类似于 #if defined(__GNUC__) & ...