2021牛客OI赛前集训营-提高组(第二场)第三题 树数树题解
题目描述
牛牛有一棵
我们称一个长度为
, 为 的祖先或 是 的祖先
你需要帮助牛牛求出最长的序列长度。
输入格式
第一行一个正整数
对于每组数据第一行一个正整数
接下来
输出格式
样例
输入样例1
18 5 3 1 5 4 5 2 5 1 6 8 7 7 6
输出样例1
7
数据范围
对于 100% 的数据,
简化题意
有一棵树,你可以跳到一个祖先,也可以跳到一个子孙,不能走重复的点,求最长路径。
正解
一开始看错题了,以为祖先=父亲,那就是树的直径!脑残题!
越看越不对劲......大家好好读题啊......
容易想到一个树形DP,我们设置
那么我们的走法显然是
显然我们应该让
然后这里有一个误区,就是
而这个部分很大,比
那这里我们怎么维护呢?
不难发现,其实我们只需要找出
注意:选择之后要将这个值在线段树上清零吗,防止在下一次选择中被选择。
然后,我当了一回大聪明:
虽然丰富人生阅历,但是时间慢+代码长+空间大,我现在感觉我是弱智......
我们的时间复杂度是
比较正常的代码
#include <bits/stdc++.h> using namespace std; struct node { int nxt, to; } a[200005]; struct tree { int l, r, mx, mpos; } tr[400005]; int t, n, h[100005], tot, x, y, f[100005], ans, num[100005], num2[100005], sz[100005], cnt; void build(int pos, int l, int r) { tr[pos].l = l, tr[pos].r = r; if (l == r) { tr[pos].mpos = l; return; } int mid = (l + r) / 2; build(pos * 2, l, mid); build(pos * 2 + 1, mid + 1, r); tr[pos].mpos = l; } void update(int pos, int x, int y) { if (x < tr[pos].l || tr[pos].r < x) return; if (tr[pos].l == tr[pos].r && tr[pos].l == x) { tr[pos].mx = y; return; } update(pos * 2, x, y); update(pos * 2 + 1, x, y); if (tr[pos * 2].mx > tr[pos * 2 + 1].mx) { tr[pos].mx = tr[pos * 2].mx; tr[pos].mpos = tr[pos * 2].mpos; } else { tr[pos].mx = tr[pos * 2 + 1].mx; tr[pos].mpos = tr[pos * 2 + 1].mpos; } } int query(int pos, int l, int r) { if (r < tr[pos].l || tr[pos].r < l) return 0; if (l <= tr[pos].l && tr[pos].r <= r) { return tr[pos].mpos; } int lm = query(pos * 2, l, r), rm = query(pos * 2 + 1, l, r); if (f[num2[lm]] > f[num2[rm]]) return lm; else return rm; } void add(int x, int y) { tot++; a[tot].to = y; a[tot].nxt = h[x]; h[x] = tot; } void dfs(int x, int fa) { num[x] = ++cnt, num2[cnt] = x; for (int i = h[x]; i; i = a[i].nxt) { if (a[i].to == fa) continue; dfs(a[i].to, x); sz[x] += sz[a[i].to]; } sz[x]++; } void dfs2(int x, int fa) { for (int i = h[x]; i; i = a[i].nxt) { if (a[i].to == fa) continue; dfs2(a[i].to, x); } int mx = 0, sum = 0; for (int i = 1; i <= 2; i++) { mx = query(1, num[x], num[x] + sz[x] - 1); if (num2[mx] != x && f[num2[mx]] != 0) { sum += f[num2[mx]]; f[num2[mx]] = 0; update(1, mx, 0); } } f[x] = 1 + sum, ans = max(ans, f[x]); update(1, num[x], f[x]); } int main() { scanf("%d", &t); while (t--) { scanf("%d", &n); memset(h, 0, sizeof(h)); memset(a, 0, sizeof(a)); memset(f, 0, sizeof(f)); memset(tr, 0, sizeof(tr)); memset(sz, 0, sizeof(sz)); tot = 0, ans = 0, cnt = 0; for (int i = 1; i <= n - 1; i++) { scanf("%d%d", &x, &y); add(x, y); add(y, x); } build(1, 1, n), dfs(1, 0), dfs2(1, 0); printf("%d\n", ans); } }
考场代码
#include<bits/stdc++.h> using namespace std; struct node { long long nxt,to; }a[200005]; struct tree { long long l,r,mx,mpos; }tr[1000005]; long long t,n,h[100005],tot,x,y,f[100005],ans,vis[100005],num[100005],num2[100005],sz[100005],cnt; stack<pair<long long,long long> >s; void build(long long pos,long long l,long long r) { tr[pos].l=l,tr[pos].r=r; if(l==r) { tr[pos].mpos=l; return; } long long mid=(l+r)/2; build(pos*2,l,mid); build(pos*2+1,mid+1,r); tr[pos].mpos=l; } void update(long long pos,long long x,long long y) { if(x<tr[pos].l||tr[pos].r<x)return; if(tr[pos].l==tr[pos].r&&tr[pos].l==x) { tr[pos].mx=y; return; } update(pos*2,x,y); update(pos*2+1,x,y); if(tr[pos*2].mx>tr[pos*2+1].mx) { tr[pos].mx=tr[pos*2].mx; tr[pos].mpos=tr[pos*2].mpos; } else { tr[pos].mx=tr[pos*2+1].mx; tr[pos].mpos=tr[pos*2+1].mpos; } } long long query(long long pos,long long l,long long r) { if(r<tr[pos].l||tr[pos].r<l)return 0; if(l<=tr[pos].l&&tr[pos].r<=r) { return tr[pos].mpos; } long long lm=query(pos*2,l,r),rm=query(pos*2+1,l,r); if(f[num2[lm]]>f[num2[rm]])return lm; else return rm; } void add(long long x,long long y) { tot++; a[tot].to=y; a[tot].nxt=h[x]; h[x]=tot; } int main() { scanf("%lld",&t); while(t--) { scanf("%lld",&n); memset(h,0,sizeof(h)); memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); memset(vis,0,sizeof(vis)); memset(tr,0,sizeof(tr)); memset(sz,0,sizeof(sz)); memset(num,0,sizeof(num)); memset(num2,0,sizeof(num2)); while(!s.empty())s.pop(); tot=0,ans=0,cnt=0; for(int i=1;i<=n-1;i++) { scanf("%lld%lld",&x,&y); add(x,y); add(y,x); } s.push({1,0}); while(!s.empty()) { long long x=s.top().first,fa=s.top().second; if(num[x]==0)num[x]=++cnt,num2[cnt]=x; for(int i=h[x];i;i=a[i].nxt) { if(a[i].to==fa)continue; if(!vis[a[i].to])s.push({a[i].to,x}); } if(s.top().first==x) { for(int i=h[x];i;i=a[i].nxt) { if(a[i].to==fa)continue; sz[x]+=sz[a[i].to]; } sz[x]++,vis[x]=1; s.pop(); } } memset(vis,0,sizeof(vis)); build(1,1,n); s.push({1,0}); while(!s.empty()) { long long x=s.top().first,fa=s.top().second; for(int i=h[x];i;i=a[i].nxt) { if(a[i].to==fa)continue; if(!vis[a[i].to])s.push({a[i].to,x}); } if(s.top().first==x) { long long mx=0,sum=0; for(int i=1;i<=2;i++) { mx=query(1,num[x],num[x]+sz[x]-1); if(num2[mx]!=x&&f[num2[mx]]!=0) { sum+=f[num2[mx]]; f[num2[mx]]=0; update(1,mx,0); } } f[x]=1+sum; ans=max(ans,f[x]); update(1,num[x],f[x]); vis[x]=1,s.pop(); } } printf("%lld\n",ans); } }
如果觉得不错的话,就给一个赞吧!
作者是 DengDuck ,转载请注明出处
文章链接: https://www.cnblogs.com/dengduck/p/17353451.html
感谢您阅读!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧