题目链接: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. 修改mysql配置中my.conf中max_allowed_packet变量

    mysql根据配置文件会限制server接受的数据包大小. 有时候大的插入和更新会受max_allowed_packet 参数限制,导致写入或者更新失败. 查看目前配置 show VARIABLES ...

  2. (转)logback配置详解

    找到一篇很详细的关于logback配置的介绍: 贴上原文链接:logback使用配置详解 1.介绍 Logback是由log4j创始人设计的另一个开源日志组件,它当前分为下面下个模块: logback ...

  3. JAVA第一次blog总结

    JAVA第一次blog总结 0.前言 大一下学期我们开展了OPP这门课程,这也是我们第一次接触到JAVA.与上学期我们在学校里学C语言不同的是,这学期由于疫情原因我们是以网课的方式在学习.在学习中我发 ...

  4. USACO Training Section 1.1 贪婪的送礼者Greedy Gift Givers

    P1201 [USACO1.1]贪婪的送礼者Greedy Gift Givers 题目描述 对于一群(NP个)要互送礼物的朋友,GY要确定每个人送出的钱比收到的多多少.在这一个问题中,每个人都准备了一 ...

  5. MySQL 增删改查(单表)

    1.sql 新增语句 表中插入数据 insert into + 表名 values(字段1value1,字段2value1,字段3value1),(字段1value2,字段2value2,字段3val ...

  6. python(random 模块)

     一.Random 模块 注意:random() 是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法. 1.random.random() 返回随机生成的一个 ...

  7. predixy源码学习--开篇

    最近开始研究predixy.predixy是一款高性能全功能redis代理 ,网上有的文章大部分都是功能上的介绍,很少有源码相关的分享. predixy的相关介绍在github: https://gi ...

  8. <学习笔记: Django之初见>

    Django 1. web框架介绍 具体介绍Django之前,必须先介绍WEB框架等概念. web框架: 别人已经设定好的一个web网站模板,你学习它的规则,然后“填空”或“修改”成你自己需要的样子. ...

  9. 线段树 离散化 E. Infinite Inversions E. Physical Education Lessons

    题目一:E. Infinite Inversions 这个题目没什么思维量,还比较简单,就是离散化要加上每一个值的后面一个值,然后每一个值放进去的不是1 ,而是这个值与下一个点的差值. 因为这个数代表 ...

  10. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...