Aizu - 2170 Marked Ancestor
题意:给出一颗树,有两种操作:
1. mark u 标记结点u
2.query u 询问离u最近的且被标记的祖先结点是哪个
让你输出所有询问的和。
显然一个暴力的做法是每次都直接修改,然后查询的话就一个一个地向祖先查询,直到一个被标记过的点.
让我们来优化一下这个暴力.
类似于一个题https://www.luogu.com.cn/problem/P1653
考虑反着搞,如果一个点的最早被标记时间比当前时间大或者根本没有被标记,那么这个点以后都不会用到了,可以被路径压缩掉.
#include<cmath> #include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<cstring> #include<map> #include<queue> #include<set> #include<vector> #include<bitset> using namespace std; const int maxn=100005; int vis[maxn],fa[maxn],n,Q,cnt; long long ans; struct query { int t,id; }q[maxn]; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void write(long long a) { if(a<0) { char a='-',b='1'; putchar(a); putchar(b); } else { if(a>=10) write(a/10); putchar(a%10+'0'); } } int find(int id,int t) { return vis[id]<t?id:fa[id]=find(fa[id],t); } int main() { while(scanf("%d%d",&n,&Q)==2&&n&&Q) { for(int i=2;i<=n;++i) fa[i]=read(),vis[i]=1e9; ans=cnt=0; for(int i=1;i<=Q;++i) { char ch; cin>>ch; int x=read(); if(ch=='Q') q[++cnt].t=i,q[cnt].id=x; else vis[x]=min(vis[x],i); } for(int i=cnt;i>=1;--i) ans+=find(q[i].id,q[i].t); write(ans); putchar('\n'); } return 0; }
当然,这仍然是个暴力(虽然在Aizu上面过了),比如树退化成一条链且每一次都查询叶子节点而不修改,就可以被卡到n方.
这里有一篇线段树维护的,大家可以看一下.
EntyEnty520~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)