2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】

1|0正题

题目链接:https://ac.nowcoder.com/acm/contest/7609/C


1|1题目大意

给出n个点的一棵树,m个时刻各有一个操作

  1. 标记一个点,每个点被标记后的每一个时刻会标记掉周围的点。
  2. 删去所有点的标记
  3. 询问一个点是否有标记

1|2解题思路

考虑没有二操作怎么搞,可以理解为标记代表起点,然后跑一遍最短路求出每个点被标记的最短时间。

如果有二操作的话是不是就很麻烦了,因为它像一个分割符一样切开两段操作。

那么就直接分开操作就好了!对于每段操作的所有点建立虚树,然后跑最短路就好了。

时间复杂度O(nlogn),因为是树就用我们的老朋友SPFA就好了

正解是定期重构+SPFA的,懒得写


1|3code

#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; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14608421.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(69)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示