Gym101630L Laminar Family
题目链接: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的更多相关文章
- NEERC2017:L - Laminar Family
传送门 很容易想到,离线按路径长度从大到小排个序,用树链剖分加颗支持区间cover的线段树就好了 代码: #include<cstdio> #include<iostream> ...
- 【FLUENT案例】01:T型管混合器中的流动与传热
案例目录 1 引子1.1 案例描述1.2 案例学习目标2 计算仿真目标3 启动FLUENT并读入网格4 FLUENT工作界面5 网格缩放及检查6 修改单位7 设置模型8 定义新材料9 计算域设置10 ...
- CFD计算
47 求解器为flunet5/6在设置边界条件时,specify boundary types下的types中有三项关于interior,interface,internal设置,在什么情况下设置相应 ...
- Y+的一些讨论
一.关于 fluent计算时壁面函数法和网格的关系,还有一个小问题 1:各位用 fluent的同仁和高手们,我想要比较好的使用 fluent软件,最重要的就是要学好理 论,在这里我想请教各位一个问题, ...
- X-Plane飞行模拟资源整理一
计划开一个博客整理一下飞行仿真软件二次开发的相关内容 预计将陆续介绍X-Plane.Microsoft Flight Simulator.FlightGear三个主流飞行模拟器. 此处为目录(占坑,随 ...
- 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 ...
- NEERC-2017
A. Archery Tournament 用线段树套set维护横坐标区间内的所有圆,查询时在$O(\log n)$个set中二分查找即可. 时间复杂度$O(n\log^2n)$. #include& ...
- 【做题】neerc2017的A、C、I、L
A - Archery Tournament 一开始往化简公式的方向去想,结果没什么用. 考虑与一条垂线相交的圆的个数.不难YY,当圆的个数最多时,大概就是这个样子的: 我们稍微推一下式子,然后就能发 ...
- lammps模拟化学反应(1)
1. Can I use lammps to chemical reaction systems?Please note that you can only get as good an answer ...
随机推荐
- 【深入AQS原理】我画了35张图就是为了让你深入 AQS
申明 本文首发自公众号:程序员cxuan,此文章为本人投稿文章.已经和cxuan沟通,文章投递公众号,博客平台我自己发布可标记为原创. 此文章肝了很久,图片较多,希望大家喜欢. 另外,感兴趣的小伙伴可 ...
- Linux 用户管理和提权
Linux ⽀持多个⼈使⽤同⼀个⽤户登录系统, Windows 在修改组策略的情况下,也可以多个⼈使⽤同⼀个⽤户登录 远程连接Linux的⽅式:SSH协议 远程连接Windows的⽅式:RDP协议 安 ...
- Git 常见问题汇总
git reabse 合并多个commit git rebase -i HEAD~{NUM} git rebase -i start end 会进入一个指定区间的commit列表 根据提示进行文本编辑 ...
- SVN签出,回退
2019独角兽企业重金招聘Python工程师标准>>> yum install -y subversion 安装SVN 签出代码 : [root@test svn]# svn che ...
- Process Synchronization-Example 1
问题描述 把学生和监考老师都看作进程,学生有N人,教师1人.考场门口每次只能进出一个人,进考场原则是先来先进.当N个学生都进入考场后,教师才能发卷子.学生交卷后可以离开考场,教师要等收上来全部卷子并封 ...
- C语言编程入门题目--No.8
题目:输出9*9口诀. 1.程序分析:分行与列考虑,共9行9列,i控制行,j控制列. 2.程序源代码: #include "stdio.h" main() { int i,j,re ...
- CodeForces - 1058D D. Vasya and Triangle
D. Vasya and Triangle time limit per test1 second memory limit per test256 megabytes inputstandard i ...
- codeforce 227E 矩阵快速幂求斐波那契+N个连续数求最大公约数+斐波那契数列的性质
E. Anniversary time limit per test2 seconds memory limit per test256 megabytes inputstandard input o ...
- P4720【模板】扩展卢卡斯,P2183 礼物
扩展卢卡斯定理 最近光做模板了 想了解卢卡斯定理的去这里,那题也有我的题解 然而这题和卢卡斯定理并没有太大关系(雾 但是,首先要会的是中国剩余定理和exgcd 卢卡斯定理用于求\(n,m\)大,但模数 ...
- Python(Pyautogui 模块)
1.安装 pyautogui 模块 pip install pyautogui 2.pyautogui 模块相关操作 鼠标操作 # 获取屏幕宽和高 w,h = pyautogui.size() # 在 ...