首页 > 其他分享 >树(更新中....)

树(更新中....)

时间:2023-03-19 23:45:01浏览次数:36  
标签:head int .... dfs fa maxn 更新 include

Problem - C - Codeforces

思路:树的重心,判断一个重心和两个重心的情况。当存在两个重心时,两个重心必相邻。只需把其中一个重心的边连在另一个重心上即可。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1e5+10;
int n;
int sz[maxn];
int sum[maxn];
int fa[maxn];
int r1,r2;
int mx=1e9;
vector <int > g[maxn];
void dfs(int u,int f)
{
    sz[u]=1;
    sum[u]=0;
    for(auto v:g[u])
    {
        if(v==f) continue;
        dfs(v,u);
        sz[u]+=sz[v];
        sum[u]=max(sum[u],sz[v]);
    }
    sum[u]=max(sum[u],n-sz[u]);
    if(sum[u]==mx)
    {
        r2=u;
    }
    if(sum[u]<mx)
    {
        r1=u;
        r2=0;
        mx=sum[u];
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        r1=r2=0;
        cin>>n;
        for(int i=0;i<=n;i++)
        {
            mx=1e9;
            sz[i]=sum[i]=fa[i]=0;
            g[i].clear();
        }
        for(int i=1;i<n;i++)
        {
            int x,y;
            cin>>x>>y;
            g[x].push_back(y);
            g[y].push_back(x);
        }
        dfs(1,-1);
        if(!r2)
        {
            int u=r1;
            int v=g[u][0];
            cout<<u<<" "<<v<<endl;
            cout<<u<<" "<<v<<endl;
        }
        else
        {
            int v;
            for(int i=0;i<g[r2].size();i++)
            {
                if(g[r2][i]!=r1)
                {
                    v=g[r2][i];
                    break;
                }
            }
            cout<<r2<<" "<<v<<endl;
            cout<<r1<<" "<<v<<endl;
        }
    }
}

核心城市

P5536 【XR-3】核心城市 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:显然求与核心城市的距离最大的城市,其与核心城市的距离最小那么k座城市一定在树的直径上。然后我们以这个直径的中点为根,把其他节点按照以这个节点为根的子树中节点的最大深度-这个点的深度排序选前$k−1$个节点即可

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1e5+10;
int n,k;
int c;
int r1,r2;
int d[maxn];
int md[maxn];
int fa[maxn];
int ans[maxn];
vector <int > g[maxn];
vector <int > path;
void dfs(int u,int f)
{
    for(auto v:g[u])
    {
        if(v==f) continue;
        d[v]=d[u]+1;
        fa[v]=u;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
}
void dfs1(int u,int f)
{
    md[u]=d[u];
    for(auto v:g[u])
    {
        if(v==f) continue;
        d[v]=d[u]+1;
        dfs1(v,u);
        md[u]=max(md[u],md[v]);
    }
}
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n>>k;
    for(int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs(1,-1);
    r1=c;
    d[c]=0,dfs(c,-1);
    r2=c;
    for(int i=1;i<=(d[c]+1)/2;i++) r2=fa[r2];
    d[r2]=0;
    dfs1(r2,-1);
    for(int i=1;i<=n;i++) ans[i]=md[i]-d[i];
    sort(ans+1,ans+1+n,cmp);
    int sum=0;
    for(int i=k+1;i<=n;i++) sum=max(sum,ans[i]+1);
    cout<<sum<<endl;
}

Three Paths on a Tree

Problem - 1294F - Codeforces

思路:首先这三个点中其中两个点一定是这棵树直径的端点,其次在直径外找一点离两个端点距离最远即可

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 2e5+10;
vector <int > g[maxn];
int n,c;
int d[maxn];
int d1[maxn];
int d2[maxn];
int fa[maxn];
int vis[maxn];
int ans3;
int ans=0;
void dfs(int u,int f)
{
    for(auto v:g[u])
    {
        if(v==f) continue;
        d[v]=d[u]+1;
        fa[v]=u;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
    return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n;
    for(int i=1;i<n;i++)
    {
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    dfs(1,-1);
    int ans1=c;
    d[c]=0,dfs(c,-1);
    int ans2=c;
    for(int i=1;i<=n;i++) d1[i]=d[i];
    d[ans2]=0;
    dfs(ans2,-1);
    for(int i=1;i<=n;i++) d2[i]=d[i];

    for(int i=1;i<=n;i++)
    {
        if(i==ans1||i==ans2) continue;
        if(d1[i]+d2[i]>d1[ans3]+d2[ans3]) ans3=i;
    }
    ans=d1[ans3]+d2[ans3]+d1[ans2];
    ans/=2;
    cout<<ans<<endl;
    cout<<ans1<<" "<<ans2<<" "<<ans3<<endl;
}

逃学的小孩

[P4408 NOI2003] 逃学的小孩 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:既然要要求耗时最长,那么就假定AB两点恰好为该树直径的端点,然后遍历找耗时最大的点即可

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
struct edge{
    int v,w,net;
}e[maxn*2];
int head[maxn];
int cnt;
int n,m;
int r1,r2;
int c;
ll d[maxn];
ll d1[maxn];
ll d2[maxn];
int fa[maxn];
void add(int u,int v,int w)
{
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].net=head[u];
    head[u]=cnt;
}
void dfs(int u,int ff)
{
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==ff) continue;
        d[v]=d[u]+e[i].w;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
    return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,-1);
    r1=c;d[c]=0;
    dfs(c,-1);
    r2=c;
    for(int i=1;i<=n;i++) d1[i]=d[i];
    d[c]=0;
    dfs(c,-1);
    for(int i=1;i<=n;i++) d2[i]=d[i];

    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=max(min(d1[i],d2[i])+d1[r2],ans);
    }
    cout<<ans<<endl;
}

树网的核

[P1099 NOIP2007 提高组] 树网的核 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:先找出该树的直径,对该直径进行尺取,计算每条路径的偏心距,取最大值

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <deque>
using namespace std;
const int maxn = 310;
struct edge{
    int v,w,net;
}e[maxn*2];
int head[maxn];
int d[maxn];
int fa[maxn];
int vis[maxn];
int q[maxn];
int c,n,s;
int cnt;
void add(int u,int v,int w)
{
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].net=head[u];
    head[u]=cnt;
}
void dfs(int u,int ff)
{
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==ff||vis[v]) continue;
        fa[v]=u;
        d[v]=d[u]+e[i].w;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n>>s;
    vector <int > path(n+1);
    for(int i=1;i<n;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,-1);
    d[c]=0,fa[c]=0;dfs(c,-1);
    int r=c;
    int ans=1e9;
    for(int i=c,j=c;i;i=fa[i])
    {
        while(d[j]-d[i]>s) j=fa[j];
        int x=max(d[c]-d[j],d[i]);
        ans=min(ans,x);
    }
    for(int i=r;i;i=fa[i]) vis[i]=1;
    for(int i=r;i;i=fa[i])
    {
        c=i;
        d[i]=0;
        dfs(i,fa[i]);
    }
    for(int i=1;i<=n;i++) ans=max(ans,d[i]);
    cout<<ans<<endl;
}

巡逻

350. 巡逻 - AcWing题库

思路:题目意思大致是构建一个或两个环,在一颗树中从一个点开始遍历所有点并返回的代价为$2(n-1)$。当$k=1$时,只要将该树的直径两个端点链接便可的到最小值$2(n-1)-d1+1$。当$k=2$,在$k=1$的操作下,找到除了直接$d1$外最长的边即可。只要将直径$d1$上的所有边权改为-1,然后用树上dp就直径,最后答案为$2*(n-1)-d1+1-d2+1$.

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 1e5+10;
struct node{
    int v,w,net;
}e[2*maxn];
int head[maxn];
int tot;
int c;
int r1,r2;
int d[maxn];
int vis[maxn];
int d1[maxn],d2[maxn];
int ans;
int fa[maxn];
int fe[maxn];
void add(int u,int v,int w)
{
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].net=head[u];
    head[u]=tot;
}
void dfs(int u,int ff)
{
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==ff||vis[v]) continue;
        vis[v]=1;
        fa[v]=u;
        fe[v]=i;
        d[v]=d[u]+e[i].w;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
}
void dfs1(int u,int ff)
{
    d1[u]=0,d2[u]=0;
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==ff||vis[v]) continue;;
        vis[v]=1;
        dfs1(v,u);
        int t=d1[v]+e[i].w;
        if(t>d1[u])
        {
            d2[u]=d1[u];
            d1[u]=t;
        }
        else if(t>d2[u])
        {
            d2[u]=t;
        }
    }
    ans=max(ans,d1[u]+d2[u]);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n,k;
    cin>>n>>k;
    for(int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        add(x,y,1);
        add(y,x,1);
    }
    dfs(1,-1);
    d[c]=0,r1=c,fa[c]=0;
    memset(vis,0,sizeof vis);
    dfs(c,-1);
    r2=c;
    if(k==1)
    {
        int s=2*(n-1)-d[c]+1;
        cout<<s<<endl;
        return 0;
    }
    for(int i=r2;i!=r1;i=fa[i])
    {
        int id=fe[i];
        e[id].w=-1;
        e[id+((id&1)?1:-1)].w=-1;
    }
    fa[1]=0;
    memset(vis,0,sizeof vis);
    dfs1(1,-1);
    int s=0;
    s=2*(n-1)-d[c]+1-ans+1;
    cout<<s<<endl;
}

HXY造公园

P2195 HXY造公园 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:对于问题一,直接dfs找直径即可。对于问题二,用并查集维护连通块,若不在同一个连通快上,则新形成的连通快的直径为$dis[fy]=max(max((dis[fx]+1)/2+(dis[fy]+1)/2+1,dis[fy]),dis[fx]);$

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 3e5+10;
vector <int > g[maxn];
int n,m,q;
int s=0;
int v=-1;
int dis[maxn];
int fa[maxn];
int vis[maxn];
int c;
int find(int x)
{
    return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx==fy) return ;
    fa[fx]=fy;
}
void dfs(int u,int f,int d)
{
    if(d>v) v=d,c=u;
    for(auto v:g[u])
    {
        if(v==f) continue;
        dfs(v,u,d+1);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n>>m>>q;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
        merge(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(fa[i]!=i) continue;
        v=-1;
        dfs(i,-1,0);
        v=-1;
        dfs(c,-1,0);
        dis[i]=v;
    }
    while(q--)
    {
        int op;
        cin>>op;
        if(op==1)
        {
            int x;
            cin>>x;
            cout<<dis[find(x)]<<endl;
        }
        else
        {
            int x,y;
            cin>>x>>y;
            int fx=find(x);
            int fy=find(y);
            if(fx==fy) continue;
            dis[fy]=max(max((dis[fx]+1)/2+(dis[fy]+1)/2+1,dis[fy]),dis[fx]);
            merge(x,y);
        }
    }
    return 0;
}

直径

389. 直径 - AcWing题库

思路:先找到该树的直径,并记录路径上的点,然后从路径上每一个点再次dfs,然后从每个点再次DFS
显然如果从某个点出发,能找到第二条与当前一边直径长度相等的一条路径,那么这条边就为可行边
分别从左右出发找一下即可。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
struct edge{
    int v;
    ll w;
    int net;
}e[maxn*2];
int head[maxn];
ll sum[maxn];
ll val[maxn];
int arr[maxn];
int vis[maxn];
int tot;
int fa[maxn];
int c,r1,r2;
ll d[maxn];
void add(int u,int v,ll w)
{
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].net=head[u];
    head[u]=tot;
}
void dfs(int u,int ff)
{
    for(int i=head[u];i;i=e[i].net)
    {
        int v=e[i].v;
        if(v==ff||vis[v]) continue;
        d[v]=d[u]+e[i].w;
        fa[v]=u;
        if(d[v]>d[c]) c=v;
        dfs(v,u);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v; ll w;
        cin>>u>>v>>w;
        add(u,v,w);add(v,u,w);
    }
    dfs(1,-1);
    d[c]=0,fa[c]=0,r1=c;
    dfs(c,-1);
    r2=c;
    int cnt=0;
    for(int i=r2;i;i=fa[i])
    {
        vis[i]=1;
        arr[++cnt]=i;
    }
    reverse(arr+1,arr+1+cnt);
    for(int i=1;i<=cnt;i++)
    {
        sum[i]=d[arr[i]];
    }
    for(int i=1;i<=cnt;i++)
    {
        d[arr[i]]=0;
        c=arr[i];
        dfs(arr[i],-1);
        val[i]=d[c];
    }
    int l=1,r=cnt;
    for(int i=1;i<=cnt;i++)
    {
        if(val[i]==sum[i]) l=i;
    }
    for(int i=cnt;i>=1;i--)
    {
        if(val[i]==sum[cnt]-sum[i]) r=i;
    }
    cout<<sum[cnt]<<endl<<r-l<<endl;
}

标签:head,int,....,dfs,fa,maxn,更新,include
From: https://www.cnblogs.com/Yuuu7/p/17234864.html

相关文章

  • 【转载】MySQL:多个事务更新同一行数据时,通过加行锁避免脏写的
    【转载】MySQL:多个事务更新同一行数据时,通过加行锁避免脏写的引入多个事务并发运行的时候,如果同时要读写一批数据,此时读和写事件的关系需要协调好,否则可能会有脏读、不......
  • nacos原理(二)更新Spring容器对象
    Spring容器感知分为两部分。第一部分是更新Environment、第二部分是注册到Spring容器的对象感知。1.更新Environment上文知道对于配置发生改变会调用发送newRefres......
  • Windows系统常见问题(不断更新)
    1、恢复快捷方式的小箭头及“快捷方式”字样。导入如下注册表内容:WindowsRegistryEditorVersion5.00[HKEY_CLASSES_ROOT\lnkfile]"IsShortcut"=""[HKEY_CURRENT_USE......
  • 【Lua】ToLua逻辑热更新
    1前言​Lua基础语法中系统介绍了Lua的语法体系,xLua逻辑热更新中介绍了xLua的应用,本文将进一步介绍Unity3D中基于ToLua实现逻辑热更新。​逻辑热更新......
  • 【Lua】xLua逻辑热更新
    1前言​Lua基础语法中系统介绍了Lua的语法体系,ToLua逻辑热更新中介绍了ToLua的应用,本文将进一步介绍Unity3D中基于xLua实现逻辑热更新。​逻辑热更新......
  • 华为认证H12-821题库(带解析且包更新)
    1、​(单选题)下面关于0SPF的特殊区域,描述错误的是:60084943A.   ​​TotallyStubArea允许ABR发布缺省的三类LSA,不接受五类LSA和细化三类LSA​​A.   ​​NSSAAre......
  • .NET应用系统的国际化-基于Roslyn抽取词条、更新代码
    上篇文章我们介绍了VUE+.NET应用系统的国际化-多语言词条服务系统国际化改造整体设计思路如下:提供一个工具,识别前后端代码中的中文,形成多语言词条,按语言、界面、模块统......
  • Minecraft基岩版编辑器已加入预览版,离正式更新指日可待
    Minecraft基岩版编辑器已加入预览版,离正式更新指日可待StarmoeのBlog[TLSD]最近更新了Minecraft的基岩预览版,出了不少新东西,而最受人瞩目的,就是大名鼎鼎的原生世界编......
  • webpack原理(1):Webpack热更新实现原理代码分析
    热更新,主要就是把前端工程文件变更,即时编译,然后通知到浏览器端,刷新代码。服务单与客户端通信方式有:ajax轮询,EventSource、websockt。客户端刷新一般分为两种:整体页面刷新,......
  • webpack原理(1):Webpack热更新实现原理代码分析
    热更新,主要就是把前端工程文件变更,即时编译,然后通知到浏览器端,刷新代码。服务单与客户端通信方式有:ajax轮询,EventSource、websockt。客户端刷新一般分为两种:整体页......