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 ...
随机推荐
- Spring Boot 整合 Spring Security,用户登录慢
场景 Spring Boot + Spring Security搭建一个Web项目. 临时用了inMemoryAuthentication. @EnableWebSecurity public cla ...
- 【集群实战】fatab开机挂载失败案例
1. nfs挂载加入fstab案例 NFS客户端实现fstab开机自启动挂载 现象:nfs开机挂载卸载了/etc/fstab中,结果无法开机自动挂载nfs 解答:1. nfs客户端命令放在/etc/r ...
- 桌面上的Flutter:Electron又多了个对手
从本质上看,Flutter是一个独立的二进制可执行文件.它不仅改变了移动设备的玩法,在桌面设备上也同样不可小觑.一次编写,可在Android.iOS.Windows.Mac和Linux上进行原生部署, ...
- java中异常的处理
异常分为运行时的异常和检测异常: java提供了两种异常机制.一种是运行时异常(RuntimeExepction),一种是检查式异常(checked execption). 运行时的异常就是在java ...
- UVA352 The Seasonal War
本文为UserUnknown原创 题目本身不难理解,就是深搜(或广搜,有可能以后会加在这里). 但是洛谷的题目中没有截到输入输出的格式,下面是我从UVA复制下来的样例: Sample input 6 ...
- spring mvc 中使用session
举例:用户登录成功之后,把用户对象放置到session中 第一步,用户登录成功之后把用户对象首先放到Model中 第二步,要在控制器上加SessionAttributes注解,把放到model中的对象 ...
- SpringCloudGateWay学习 之 从函数式编程到lambda
文章目录 前言: 函数式编程: 什么是函数式编程: 函数式编程的特点 lambda表达式: 核心: 函数接口: 方法引用: 类型推断: 变量引用: 级联表达式跟柯里化: 前言: 这一系列的文章主要是为 ...
- 使用天祥TX-1C调试DS18B20温度传感器的收获
翻查DS18B20的DataSheet编写操作函数,其过程遇到了不少坎,记下来备查. 对于单总线的DS18B20芯片,首先严格按照时序图写出正确的“写0”.“写1”和“读0.1”的基础函数,再以此写出 ...
- Mysql常用sql语句(八)- where 条件查询
测试必备的Mysql常用sql语句,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1683347.html 前言 ...
- 今天主要做的是Remember Me(记住我)功能的实现
功能就是让网站登录过的人只要不注销,下次打开网站之后直接进入,不用重复登录,此功能主要是session与cookie的配合运用,具体实现是这样的,在登录页面判断并完成登录,然后将所需数据写入sessi ...