题面

传送门

重要思想

真的是没想到,我很久以来一直以为总会有应用的$BFS$序,最终居然是以这种方式出现在题目中

笔记:$BFS$序可以用来处理限制点对距离的题目(综合点分树使用)

思路

本题中首先询问可以拆成两个:所有同色点对距离大于$L-1$的种数减去所有同色点对距离大于$R$的种数

考虑如何解决点对距离大于$k-1$:

我们考虑树的$bfs$序,假设当前按照$bfs$序加入了点$u$,深度为$d$

考虑树里另外两个已经加入了的点$x,y$,显然它们的深度都小于等于$d$

那么有结论:如果$dis(x,u)\leq k$且$dis(y,u)\leq k$,那么$dis(x,y)\leq k$

结论的证明:考虑$u$到$x,y$的路径第一次分离的点

在这个点上,有两种情况:两条路都去某个儿子,或者一个去父亲一个去儿子

可以发现不论哪种情况,最终$dis(x,y)$都不超过$k$

那么我们可以把问题变成:按照$bfs$序加入点,每次每个点不能选择的颜色数等于在加入它的时候同它的距离小于$k$的点数

注意上述的点集中任意两个点的距离都小于$k$,所以一定颜色互不相同

这就避免了原图想法中可能出现“$x,y$和$y,z$颜色不同,但是$x,z$颜色一样”的情况

解决距离小于$k$的点数使用点分树即可

Code

请务必不要吐槽作者的难看的点分树写法【悲】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<queue>
#define MOD 1000000007
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,L,R,first[100010],cnte=-1;
struct edge{
int to,next;
}a[200010];
inline void add(int u,int v){
a[++cnte]=(edge){v,first[u]};first[u]=cnte;
a[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
int vis[100010],pre[100010],siz[100010],son[100010],root,sum;
int dis0[100010][20],dis1[100010][20],st[100010][20],dep[100010];
namespace BIT0{
int a[4000010],st[100010],lim[100010],cur=0;
inline void init(int u,int len){
st[u]=cur;lim[u]=len;
cur+=len;
}
inline void add(int u,int x){
x++;
for(;x<=lim[u];x+=(x&(-x))) a[st[u]+x]++;
}
inline int sum(int u,int x){
if(x<0) return 0;
x++;int re=0;
x=min(x,lim[u]);
for(;x;x^=(x&(-x))) re+=a[st[u]+x];
return re;
}
}
namespace BIT1{
int a[4000010],st[100010],lim[100010],cur=0;
inline void init(int u,int len){
st[u]=cur;lim[u]=len;
cur+=len;
}
inline void add(int u,int x){
x++;
for(;x<=lim[u];x+=(x&(-x))) a[st[u]+x]++;
}
inline int sum(int u,int x){
if(x<0) return 0;
x++;int re=0;
x=min(x,lim[u]);
for(;x;x^=(x&(-x))) re+=a[st[u]+x];
return re;
}
}
void getroot(int u,int f){
int i,v;
siz[u]=1;son[u]=0;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(vis[v]||v==f) continue;
getroot(v,u);
siz[u]+=siz[v];
if(son[u]<siz[v]) son[u]=siz[v];
}
son[u]=max(son[u],sum-siz[u]);
if(son[u]<son[root]) root=u;
}
int dfs1(int u,int f,int d,int num){
int i,v,re=d;
dis1[u][num]=d;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f||vis[v]) continue;
re=max(re,dfs1(v,u,d+1,num));
}
return re;
}
int dfs0(int u,int f,int d,int num,int root){
int i,v,re=d;
dis0[u][num]=d;st[u][num]=root;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f||vis[v]) continue;
re=max(re,dfs0(v,u,d+1,num,root));
}
return re;
}
void build(int u,int fa,int ori,int cursum){
int i,v,tmp;
dep[u]=dep[fa]+1;
if(fa){
tmp=dfs1(ori,fa,1,dep[u]);
BIT1::init(u,tmp+1);
}
tmp=dfs0(u,0,0,dep[u],u);
BIT0::init(u,tmp+1);
vis[u]=1;pre[u]=fa;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(vis[v]) continue;
sum=(siz[u]>siz[v])?siz[v]:cursum-siz[u];
root=0;son[root]=sum;
getroot(v,0);
build(root,u,v,sum);
}
}
inline void change(int u){
BIT0::add(u,0);
for(int i=dep[u]-1;i>=1;i--){
//BIT0(dis0[u][i]): u to st[u][i]
//BIT1(dis1[u][i+1]): u to st[u][i] only in subtree st[u][i+1]
BIT0::add(st[u][i],dis0[u][i]);
BIT1::add(st[u][i+1],dis1[u][i+1]);
}
}
inline int query(int u,int d){
int re=BIT0::sum(u,d),i;
for(i=dep[u]-1;i>=1;i--){
re+=BIT0::sum(st[u][i],d-dis0[u][i]);
re-=BIT1::sum(st[u][i+1],d-dis1[u][i+1]);
}
return re;
}
int bfs[100010];queue<int>q;
int main(){
memset(first,-1,sizeof(first));
n=read();m=read();L=read();R=read();int i,u,v,t1,t2;
int ans0=1,ans1=1;
for(i=1;i<n;i++){
t1=read();t2=read();
add(t1,t2);
}
root=0;sum=n;son[root]=sum;
getroot(1,0);
build(root,0,1,sum); q.push(1);bfs[1]=1;
while(!q.empty()){
u=q.front();q.pop();
t1=m-query(u,L-1);
t2=max(0,m-query(u,R));
change(u);
if(m<=0){puts("0");return 0;}
ans0=1ll*ans0*t1%MOD;
ans1=1ll*ans1*t2%MOD;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(bfs[v]) continue;
q.push(v);bfs[v]=1;
}
}
cout<<(ans0-ans1+MOD)%MOD<<'\n';
}

[NOI.AC省选模拟赛3.23] 染色 [点分治+BFS序]的更多相关文章

  1. [NOI.AC省选模拟赛3.23] 集合 [数学]

    题面 传送门 一句话题意: 给定$n\leq 1e9,k\leq 1e7,T\leq 1e9$ 设全集$U=\lbrace 1,2,3,...n\rbrace $,求$(min_{x\in S}\lb ...

  2. NOI.AC省选模拟赛第一场 T1 (树上高斯消元)

    link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...

  3. [NOI.AC省选模拟赛3.31] 星辰大海 [半平面交]

    题面 传送门 思路 懒得解释了......也是比较简单的结论 但是自己看到几何就退缩了...... 下周之内写一个计算几何的学习笔记! Code #include<iostream> #i ...

  4. [NOI.AC省选模拟赛3.31] 附耳而至 [平面图+最小割]

    题面 传送门 思路 其实就是很明显的平面图模型. 不咕咕咕的平面图学习笔记 用最左转线求出对偶图的点,以及原图中每个边两侧的点是谁 建立网络流图: 源点连接至每一个对偶图点,权值为这个区域的光明能量 ...

  5. [NOI.AC省选模拟赛3.30] Mas的童年 [二进制乱搞]

    题面 传送门 思路 这题其实蛮好想的......就是我考试的时候zz了,一直没有想到标记过的可以不再标记,总复杂度是$O(n)$ 首先我们求个前缀和,那么$ans_i=max(pre[j]+pre[i ...

  6. [noi.ac省选模拟赛]第12场题解集合

    题目 比赛界面. T1 数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算. 树上路径统计通常会用到差分方法.这里有两棵树,因此我们可以做"差分套差分",在 A 树上对 ...

  7. [noi.ac省选模拟赛]第10场题解集合

    题目 比赛界面. T1 不难想到,对于一个与\(k\)根棍子连接的轨道,我们可以将它拆分成\(k+1\)个点,表示这条轨道不同的\(k+1\)段. 那么,棍子就成为了点与点之间的边.可以发现,按照棍子 ...

  8. [noi.ac省选模拟赛]第11场题解集合

    题目   比赛界面. T1   比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配.   尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...

  9. [noi.ac省选模拟赛20200606]赌怪

    题目   点这里看题目. 分析   先特判掉\(K=2\)的情况.   首先可以考虑到一个简单 DP :   \(f(i)\):前\(i\)张牌的最大贡献.   转移可以\(O(n^2)\)地枚举区间 ...

随机推荐

  1. php中 include 、include_once、require、require_once4个语言结构的含义和区别

    对于不同页面中的相同代码部分,可以将其分离为单个文件 ,通过include引入文件. 可以提高代码的复用率 include 和include_once都有引入文件的作用 使用的语法是 :include ...

  2. 网站标题被篡改成北京赛车、PK10的解决处理办法

    客户网站于近日被跳转到赌博网站,打开后直接跳转到什么北京赛车,PK10等内容的网站上去,客户网站本身做了百度的推广,导致所有访问用户都跳转到赌博网站上去,给客户带来很大的经济损失,再一个官方网站的形象 ...

  3. Phoenix映射HBase数据表

    1. 说明 安装好phoenix后对于HBase中已经存在的数据表不会自动进行映射,所以想要再phoenix中操作HBase已有数据表就需要手动进行配置. 2. 创建HBase表 > creat ...

  4. 纯HTML+CSS实现阿童木头像

    他有十万马力,能上天能入地:他分辨善恶,是勇敢正义化身:1963年,他登上荧幕,在日本创下了未曾有过的高收视率……他叫阿童木,一个纯真.善良.勇 敢的机器娃娃.“阿童木之父”手冢治虫曾说,将阿童木生日 ...

  5. 使用JDK自带的keytool工具生成证书

    一.keytool 简介 keytool 是java用于管理密钥和证书的工具,它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及 ...

  6. 类和实例属性的查找顺序 mro查找

    如果多个类继承父类,然后又被多个类继承这种复杂的问题,可以使用 mro方法 例如: class A: pass class C(D): pass class B(D): pass class A(B, ...

  7. 【转】Linux学习(1)-常用快捷键、文件管理和查询

    原文链接:http://www.cnblogs.com/zhaopei/p/7397402.html 有话要说 为什么要用Linux?要用Linux的原因太多,想说说不完啊. 如果你说用Linux只是 ...

  8. LeetCode - 20. Valid Parentheses(0ms)

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  9. LeetCode 19——删除链表的倒数第 N 个节点

    1. 题目 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后 ...

  10. Java实现网页截屏功能(基于phantomJs)

    公司最近有个需求:把用户第一次的测量身体信息和最近一次测量信息进行对比,并且需要把对比的数据截成图片可以发给用户(需要在不打开网页的情况下实时对网页进行截图然后保存到服务器上,返回图片地址),通过网上 ...