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 ...
随机推荐
- Linux笔记(shell基础,历史命令,命令补全/别名,通配符,输出重定向)
一.shell 基础 shell是个命令解释器,提供用户和机器之间的交互 每个用户都可以拥有自己特定的shell centos7默认Shell为bash(Bourne Agin shell) 除了ba ...
- 数学--数论--HDU 5223 - GCD
Describtion In mathematics, the greatest common divisor (gcd) of two or more integers, when at least ...
- 在Jetson TX2上安装caffe和PyCaffe
caffe是Nvidia TensorRT最支持的深度学习框架,因此在Jetson TX2上安装caffe很有必要.顺便说一句,下面的安装是支持python3的. 先决条件 在Jetson TX2上完 ...
- P4430 小猴打架、P4981 父子
prufer编码 当然你也可以理解为 Cayley 公式,其实这个公式就是prufer编码经过一步就能推出的 P4430 小猴打架 P4981 父子 这俩题差不多 先说父子,很显然题目就是让你求\(n ...
- 2020最新nginx+gunicorn+supervisor部署基于flask开发的项目的生产环境的详细攻略
本攻略基于ubuntu1804的版本,服务器用的华为云的服务器,python3(python2已经在2020彻底停止维护了,所以转到python3是必须的)欢迎加我的QQ6398903,或QQ群讨论相 ...
- Java种sleep和wait的区别
1,sleep方法是Thread类的静态方法,wait()是Object超类的成员方法 2,sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时 ...
- dumpsys-package
dumpsys-package ams和pms是android系统最重要的系统服务,本文解析dumpsys package命令,看哪些PMS相关的系统信息,数据结构是运行时可以查看的. 命令提示 co ...
- PHP导出excel文件,第二步先实现自写二维数组加入模板excel文件后导出
今天主要研究数据加入EXCEL并导出的问题,先不从数据库提取数据导出,自己先写一个二维数组,然后遍历二维数组写入excel模板中导出,首先根据模板excel的内容书写对应的二维数组 $arr=arra ...
- 【FreeRTOS学习03】小白都能懂的Task Management 任务管理基本概念介绍
在FreeRTOS中,线程的术语又可以被称之为任务,或许这样更加合适,本文将介绍任务的创建/删除,任务参数的使用,以及任务优先级: 1 软实时和硬实时 硬实时系统的任务运行正确性与响应时限是紧密相关的 ...
- 对文本的内容进行排序(io流、集合操作)
package com.itheima.demo01.BufferedStream; import java.io.*; import java.util.HashMap; /* 练习: 对文本的内容 ...