题目链接:https://cn.vjudge.net/problem/Gym-101630L

题目大意:

  对于一个集合的集合,若其中任意两个集合 \(A\) 和 \(B\) 都满足下述三个条件之一:\(A \subset B\) 或 \(B \subset A\) 或 \(A \cap B = \varnothing\),则称这个集合 \(laminar\).

  给定一棵有 \(N\) 个结点的树,再给出 \(f\) 个集合,每个集合包含树上两点之间的最短路径所经过的所有点,问这 \(f\) 个集合所组成的集合是否 \(laminar\).

知识点:  LCA、树上差分前缀和

解题思路:

  首先,所有只包含一个点的集合都可以忽略,它们不影响答案。

  用树上差分前缀和求出各个点被多少条路径经过(即被多少个集合包含)。

  忽略所有没有被集合包含的点,那么剩下的点的度数不能大于 \(2\),即剩下的图都是链。对于每一条链,维护一个单调栈来验证是否满足 \(laminar\) 即可。

AC代码:

 #include <bits/stdc++.h>
using namespace std;
const int maxn = +,DEG=; /******LCA******/
int fa[maxn][DEG];
int deg[maxn];
vector<int> G[maxn];
void BFS(int root){
queue<int> que;
deg[root]=;
fa[root][]=root;
que.push(root);
while(!que.empty()){
int tmp=que.front();
que.pop();
for(int i=;i<DEG;i++)
fa[tmp][i]=fa[fa[tmp][i-]][i-];
for(int i=;i<G[tmp].size();i++){
int v=G[tmp][i];
if(v==fa[tmp][]) continue;
deg[v]=deg[tmp]+;
fa[v][]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v){
if(deg[u]>deg[v]) swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=;det;det>>=,i++){
if(det&)
tv=fa[tv][i];
}
if(tu==tv) return tu;
for(int i=DEG-;i>=;i--){
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][];
} struct Path{
int u,v,len;
}pth[maxn]; //记录路径
int cnt=;
bool cmp(const Path &a,const Path &b){
if(a.len>b.len) return true;
return false;
} /******树上差分前缀和******/
int val[maxn];
void dfs1(int rt,int last){
for(int i=;i<G[rt].size();i++){
int to=G[rt][i];
if(to!=last){
dfs1(to,rt);
val[rt]+=val[to];
}
}
} int du[maxn]; bool vis[maxn];
vector<int> Next[maxn];
int que[maxn],indx[maxn];
stack<int> endpt;
bool check(int s){
int tot=;
int now=s;
while(){//对链上的点进行编号
vis[now]=true;
bool flag=false;
indx[now]=tot;
que[tot++]=now;
for(int i=;i<G[now].size();i++){
int to=G[now][i];
if(val[to]&&!vis[to]){
now=to;
flag=true;
break;
}
}
if(!flag) break;
}
while(!endpt.empty()) endpt.pop();
for(int i=;i<tot;i++){
//单调栈维护结束结点的编号(对于每一条路径,编号小的是开始结点,编号大的是结束结点)
while(!endpt.empty()&&endpt.top()<i) endpt.pop();
int now=que[i];
for(int j=;j<Next[now].size();j++){
int to=Next[now][j];
if(indx[to]>i){
if(endpt.empty()||indx[to]<=endpt.top()) endpt.push(indx[to]);
else return false; //检查是否满足条件
}
}
}
return true;
} int main(){
// freopen("in.txt","r",stdin);
int n,f;
scanf("%d%d",&n,&f);
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
BFS();
for(int i=;i<f;i++){
int u,v;
scanf("%d%d",&u,&v);
if(u==v) continue;
pth[cnt].u=u,pth[cnt].v=v;
int tfa=LCA(u,v);
pth[cnt].len=deg[u]+deg[v]-*deg[tfa];
val[u]++,val[v]++,val[tfa]--;
if(tfa!=) val[fa[tfa][]]--;
cnt++;
}
dfs1(,);
for(int i=;i<=n;i++){
if(!val[i]) continue;
for(int j=;j<G[i].size();j++){
if(val[G[i][j]]) du[i]++; //计算每一个有被路径经过的结点的度数
}
}
for(int i=;i<=n;i++){
if(du[i]>){
printf("No\n");
return ;
}
}
sort(pth,pth+cnt,cmp);
for(int i=;i<cnt;i++){
Next[pth[i].u].push_back(pth[i].v); //记录路径
Next[pth[i].v].push_back(pth[i].u);
}
for(int i=;i<=n;i++){
if(du[i]==&&!vis[i]){
if(!check(i)){
printf("No\n");
return ;
}
}
}
printf("Yes\n");
return ;
}

Gym101630L Laminar Family的更多相关文章

  1. NEERC2017:L - Laminar Family

    传送门 很容易想到,离线按路径长度从大到小排个序,用树链剖分加颗支持区间cover的线段树就好了 代码: #include<cstdio> #include<iostream> ...

  2. 【FLUENT案例】01:T型管混合器中的流动与传热

    案例目录 1 引子1.1 案例描述1.2 案例学习目标2 计算仿真目标3 启动FLUENT并读入网格4 FLUENT工作界面5 网格缩放及检查6 修改单位7 设置模型8 定义新材料9 计算域设置10 ...

  3. CFD计算

    47 求解器为flunet5/6在设置边界条件时,specify boundary types下的types中有三项关于interior,interface,internal设置,在什么情况下设置相应 ...

  4. Y+的一些讨论

    一.关于 fluent计算时壁面函数法和网格的关系,还有一个小问题 1:各位用 fluent的同仁和高手们,我想要比较好的使用 fluent软件,最重要的就是要学好理 论,在这里我想请教各位一个问题, ...

  5. X-Plane飞行模拟资源整理一

    计划开一个博客整理一下飞行仿真软件二次开发的相关内容 预计将陆续介绍X-Plane.Microsoft Flight Simulator.FlightGear三个主流飞行模拟器. 此处为目录(占坑,随 ...

  6. Disposable microfluidic devices: fabrication, function, and application Gina S. Fiorini and Daniel T

    Disposable microfluidic devices: fabrication, function, and application Gina S. Fiorini and Daniel T ...

  7. NEERC-2017

    A. Archery Tournament 用线段树套set维护横坐标区间内的所有圆,查询时在$O(\log n)$个set中二分查找即可. 时间复杂度$O(n\log^2n)$. #include& ...

  8. 【做题】neerc2017的A、C、I、L

    A - Archery Tournament 一开始往化简公式的方向去想,结果没什么用. 考虑与一条垂线相交的圆的个数.不难YY,当圆的个数最多时,大概就是这个样子的: 我们稍微推一下式子,然后就能发 ...

  9. lammps模拟化学反应(1)

    1. Can I use lammps to chemical reaction systems?Please note that you can only get as good an answer ...

随机推荐

  1. Spring5参考指南:基于Schema的AOP

    文章目录 基于Schema的AOP 定义Aspect 定义Pointcut 定义Advice advice参数 Advisors 基于Schema的AOP 上篇文章我们讲到了使用注解的形式来使用Spr ...

  2. Pytorch中自定义神经网络卷积核权重

    1. 自定义神经网络卷积核权重 神经网络被深度学习者深深喜爱,究其原因之一是神经网络的便利性,使用者只需要根据自己的需求像搭积木一样搭建神经网络框架即可,搭建过程中我们只需要考虑卷积核的尺寸,输入输出 ...

  3. 【集群实战】sersync

    1. sersync介绍 sersync功能: 实时同步: sersync组成: sersync==inotify+rsync inotify: 监控某个目录下面"文件/目录"是否 ...

  4. Python 3之bytes新特性

    转载: Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分. 文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示. Python 3不会以任意隐式的方 ...

  5. redis- info调优入门-《每日五分钟搞定大数据》

    本文根据redis的info命令查看redis的内存使用情况以及state状态,来观察redis的运行情况以及需要作出的相应优化. info 1.memory used_memory:13409011 ...

  6. 【阅读笔记】Ranking Relevance in Yahoo Search (四 / 完结篇)—— recency-sensitive ranking

    7. RECENCY-SENSITIVE RANKING 作用: 为recency-sensitive的query提高排序质量: 对于这类query,用户不仅要相关的还需要最新的信息: 方法:rece ...

  7. socket编程之时间回射服务器

    使用到的函数: // 返回值:读到的字节数,若已到文件尾,返回0:若出错,返回-1 ssize_t read(int fd, void *buf, size_t nbytes); // 返回值:若成功 ...

  8. P1725 琪露诺(单调队列优化)

    描述:https://www.luogu.com.cn/problem/P1725 小河可以看作一列格子依次编号为0到N,琪露诺只能从编号小的格子移动到编号大的格子.而且琪露诺按照一种特殊的方式进行移 ...

  9. ztree根据参数动态控制是否显示复选框/单选框(静态JSON数据)

    本文不再更新,可能存在内容过时的情况,实时更新请访问原地址:ztree根据参数动态控制是否显示复选框/单选框(静态JSON数据): 现有全省各地区静态JSON数据,现在想通过Url参数,动态控制是否显 ...

  10. CTR预估模型演变及学习笔记

    [说在前面]本人博客新手一枚,象牙塔的老白,职业场的小白.以下内容仅为个人见解,欢迎批评指正,不喜勿喷![握手][握手] [再啰嗦一下]如果你对智能推荐感兴趣,欢迎先浏览我的另一篇随笔:智能推荐算法演 ...