2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】
正题
题目链接:https://ac.nowcoder.com/acm/contest/7609/C
题目大意
给出\(n\)个点的一棵树,\(m\)个时刻各有一个操作
- 标记一个点,每个点被标记后的每一个时刻会标记掉周围的点。
- 删去所有点的标记
- 询问一个点是否有标记
解题思路
考虑没有二操作怎么搞,可以理解为标记代表起点,然后跑一遍最短路求出每个点被标记的最短时间。
如果有二操作的话是不是就很麻烦了,因为它像一个分割符一样切开两段操作。
那么就直接分开操作就好了!对于每段操作的所有点建立虚树,然后跑最短路就好了。
时间复杂度\(O(n\log n)\),因为是树就用我们的老朋友\(\text{SPFA}\)就好了
正解是定期重构+\(\text{SPFA}\)的,懒得写
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+10,T=18;
struct node{
int to,next,w;
}a[N<<1];
int n,m,cnt,qnt,pnt,tot,top,ls[N];
int dep[N],dfn[N],f[N][T+1],s[N];
int ve[N],dis[N],t[N],p[N];
pair<int,int> q[N];bool v[N];
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void adde(int x,int y){
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=dep[y]-dep[x];
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=dep[y]-dep[x];
ve[++pnt]=x;ve[++pnt]=y;return;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1;dfn[x]=++cnt;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
f[y][0]=x;dfs(y,x);
}
return;
}
int LCA(int x,int y){
if(dep[x]>dep[y])swap(x,y);
for(int i=T;i>=0;i--)
if(dep[f[y][i]]>=dep[x])y=f[y][i];
if(x==y)return x;
for(int i=T;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
bool cmp(int x,int y)
{return dfn[x]<dfn[y];}
void Ins(int x){
if(!top){s[++top]=x;return;}
int lca=LCA(x,s[top]);
while(top>1&&dep[s[top-1]]>dep[lca])
adde(s[top-1],s[top]),top--;
if(dep[s[top]]>dep[lca])adde(lca,s[top]),top--;
if(s[top]!=lca||!top)s[++top]=lca;
s[++top]=x;return;
}
void solve(){
queue<int> q;
sort(ve+1,ve+1+pnt);
pnt=unique(ve+1,ve+1+pnt)-ve-1;
for(int i=1;i<=pnt;i++){
int x=ve[i];
if(t[x])q.push(x),v[x]=1,dis[x]=t[x];
}
while(!q.empty()){
int x=q.front();v[x]=0;q.pop();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(dis[x]+a[i].w<dis[y]){
dis[y]=dis[x]+a[i].w;
if(!v[y])q.push(y),v[y]=1;
}
}
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
dfs(1,1);
for(int j=1;j<=T;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
cnt=tot=0;m++;
memset(ls,0,sizeof(ls));
memset(dis,0x3f,sizeof(dis));
for(int z=1;z<=m;z++){
int op,x;
if(z==m)op=2;
else scanf("%d%d",&op,&x);
if(op==1){
if(!t[x])p[++cnt]=x,t[x]=z;
}
else if(op==3)q[++qnt]=mp(x,z),p[++cnt]=x;
else{
sort(p+1,p+1+cnt,cmp);
cnt=unique(p+1,p+1+cnt)-p-1;
if(p[1]!=1)s[++top]=1;
for(int i=1;i<=cnt;i++)Ins(p[i]);
while(top>1)adde(s[top-1],s[top]),top--;
solve();
for(int i=1;i<=qnt;i++){
if(dis[q[i].first]<=q[i].second)puts("wrxcsd");
else puts("orzFsYo");
}
for(int i=1;i<=cnt;i++){
int x=p[i];
ls[x]=t[x]=0;dis[x]=1e9;
}
for(int i=1;i<=pnt;i++){
int x=ve[i];
ls[x]=t[x]=0;dis[x]=1e9;
}
cnt=qnt=top=tot=pnt=0;
}
}
return 0;
}
2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】的更多相关文章
- 2020牛客NOIP赛前集训营-提高组(第二场)- B.包含 (FWT)
题面 题解 这题就是个快速沃尔什变换的模板题,输入ai时,令s[ai]=1,对s[]做一遍DWT_AND(s)(快速沃尔什正变换,按位与),然后直接访问s[x]完事. #include<map& ...
- 2020牛客NOIP赛前集训营-普及组(第二场)A-面试
面 试 面试 面试 题目描述 牛牛内推了好多人去牛客网参加面试,面试总共分四轮,每轮的面试官都会对面试者的发挥进行评分.评分有 A B C D 四种.如果面试者在四轮中有一次发挥被评为 D,或者两次发 ...
- 2020牛客NOIP赛前集训营-普及组(第二场) 题解
目录 T1 面试 描述 题目描述 输入描述: 输出描述: 题解 代码 T2 纸牌游戏 描述 题目描述 输入描述: 输出描述: 题解 代码 T3 涨薪 描述 题目描述 输入描述: 输出描述: 题解 代码 ...
- 2020牛客NOIP赛前集训营-提高组(第三场) C - 牛半仙的妹子Tree (树链剖分)
昨天教练问我:你用树剖做这道题,怎么全部清空状态呢? 我:???不是懒标记就完了??? 教练:树剖不是要建很多棵线段树吗,不止log个,你要一个一个清? 我:为什么要建很多棵线段树? ...
- 2022牛客OI赛前集训营-提高组(第一场) 奇怪的函数 根号很好用
奇怪的函数 考虑暴力,每次查询\(O(n)\)扫所有操作,修改\(O(1)\) 这启发我们平衡复杂度,考虑分块. 观察题目性质,可以发现,经过若干次操作后得到的结果一定是一个关于\(x\)的分段函数, ...
- 牛客网NOIP赛前集训营-普及组(第二场)和 牛客网NOIP赛前集训营-提高组(第二场)解题报告
目录 牛客网NOIP赛前集训营-普及组(第二场) A 你好诶加币 B 最后一次 C 选择颜色 D 合法括号序列 牛客网NOIP赛前集训营-提高组(第二场) A 方差 B 分糖果 C 集合划分 牛客网N ...
- 牛客网NOIP赛前集训营-提高组(第一场)
牛客的这场比赛感觉真心不错!! 打得还是很过瘾的.水平也比较适合. T1:中位数: 题目描述 小N得到了一个非常神奇的序列A.这个序列长度为N,下标从1开始.A的一个子区间对应一个序列,可以由数对[l ...
- 牛客网NOIP赛前集训营-提高组(第二场)A 方差
链接:https://www.nowcoder.com/acm/contest/173/A来源:牛客网 题目描述 一个长度为 m 的序列 b[1...m] ,我们定义它的方差为 ,其中 表示序列的平 ...
- [牛客网NOIP赛前集训营-提高组(第一场)]C.保护
链接:https://www.nowcoder.com/acm/contest/172/C来源:牛客网 题目描述 C国有n个城市,城市间通过一个树形结构形成一个连通图.城市编号为1到n,其中1号城市为 ...
随机推荐
- .Net Core WebApi(二)
查看当前端口暴露的所有接口信息 https://localhost:5001/.well-known/openid-configuration 拿到信息如下
- openssl生成RSA密钥证书
1.openssl的安装 2.RSA密钥证书的生成 3.openssl的常用命令 1.openssl的安装 openssl 是目前最流行的 SSL 密码库工具,其提供了一个通用.健壮.功能完备的工具套 ...
- ASP.Net Core Web Api 使用 IdentityServer4 最新版 踩坑记录
辅助工具 日志追踪包 : Serilog.AspNetCore 源码查看工具 : ILSpy 项目环境 ###: ASP.NetCore 3.1 IdentityServer4 4.0.0+ 主题内容 ...
- 辗转相除 求最大公约数!or 最小公倍数
求最大公约数和最小公倍数的经典算法--辗转相除法描述如下: 若要求a,b两数的最大公约数和最小公倍数,令a为a.b中较大数,b为较小数,算法进一步流程: while(b不为0) { temp=a%b: ...
- 2014 12 27 bestcoder 第一题
水的不行不行的一道题 也是自己做的第一道题 纪念下 1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h ...
- YARN的工作过程
yarn的工作执行流程图 1.用户向YARN中提交应用程序 2.ResourceManager为该应用程序找到一个可用的NodeManager 并分配一个Container,然后在这个Containe ...
- rest operater剩余操作符
rest叫做剩余操作符(rest operator),是解构的一种,意思就是把剩余的东西放到一个array里面赋值给它.一般只针对array的解构 //rest叫做剩余操作符(rest operato ...
- [leetcode]1109. 航班预订统计(击败100%用户算法-差分数组的详解)
执行用时2ms,击败100%用户 内存消耗52.1MB,击败91%用户 这也是我第一次用差分数组,之前从来没有碰到过,利用差分数组就是利用了差分数组在某一区间内同时加减情况,只会改变最左边和最右边+1 ...
- 一个基于activiti审批流程示例,如何与系统整合
前言 目前市场上有很多开源平台没有整合工作流,即使有,也是价格不菲的商业版,来看这篇文章的估计也了解了行情,肯定不便宜.我这个快速开发平台在系统基础功能(用户管理,部门管理-)上整合了工作流,你可以直 ...
- Linux下Oracle新建用户并且将已有的数据dmp文件导入到新建的用户下的操作流程
Oracle新建用户并且将已有的数据dmp文件导入到新建的用户下的操作流程 1.切换到oracle用户下 su - oracle 2.登录sqlplus sqlplus /nolog 3.使用sysd ...