首页 > 其他分享 >圆方树学习笔记

圆方树学习笔记

时间:2024-01-26 11:00:53浏览次数:36  
标签:tx int 笔记 edge 学习 圆方树 maxn low dfn

圆方树学习笔记

圆方树是优秀的图论算法,从仙人掌图向无向图扩展,利用割点和点双联通分量的性质,实现了图向树的转换。

对仙人掌的处理:圆方树——处理仙人掌的利器

而且实现十分简单

算法思路

前置知识

割点和桥,点双联通分量。

思路

对于一个无向图,圆方树理解可以如下:

  • 原图中点是圆点。
  • 图中的每一个点双联通分量新建一个点,这些点称为方点。
  • 删除原图中的边,每一个圆点向包含其的点双对应的方点连边。

注意:如果两点不是属于同一点双,而又有边相连,那么我们把这两点看做是一个点双。

下图是一个图示:

可以使用 tarjin 算法快速建出圆方树:

//G 是原图边,Tr 是圆方树边
void tarjin(int u)
{
    dfn[u]=low[u]=++cok;
    st[++tp]=u;
    for(int i=G.head[u];i;i=G.edge[i].nxt)
    {
        int v=G.edge[i].to;
        if(!dfn[v])
        {
            tarjin(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u])//出现点双,建方点连边
            {
                Tr.add(++tx,u);
                Tr.add(u,tx);
                int x=0;
                do
                {
                    x=st[tp--];
                    Tr.add(tx,x);
                    Tr.add(x,tx);
                }while(x!=v);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}

性质

1.圆方树上圆点只会和方点连边。

2.节点级别为 \(O(n)\)。

3.如果原图连通,那么其圆方树为一棵树。

性质1:正确性显然,方点仅会和圆点相连。

性质2:显然,原图中点双至多有 \(n\) 个,新建方点个数为 \(O(n)\) 级。关于点双至多 \(O(n)\) 个,不难发现,每次新建方点连边至少出栈一次,而每个点至多入栈一次,得证。

性质3:考虑反证法,设一直圆方树中存在环,那么环上的一个圆点至少连接两个方点,那么这个圆点至少属于两个点双。

引理:不是割点的点至多存与一个点双。阅读代码可知,不是割点的点,在构建圆方树时,与对应方点的连边出现在循环弹栈中,又至多出现一次,得证。

根据引理,环中的圆点都是割点,删除割点后图会不连通,与环的定义冲突。反证性质3成立。

实际运用

不难发现圆方树上两点之间的圆点就是任意一条简单路径都必须经过的点(割点)。

例题

例一 P4320 道路相遇

建圆方树查询两点之间圆点个数。

利用 LCA 和一下分析一下圆方树的其他性质还是挺好做的。

#include<bits/stdc++.h>
using namespace std;

const int maxm=1e6+5,maxn=5e5+5;

struct node
{
    int to,nxt;
}tredge[maxm*2],edge[maxm*2];

int n,m,trtot,tot,cok,tp,tx,q;
int dfn[maxn],low[maxn],trhead[maxm],head[maxn],deep[maxm],st[maxn],fa[maxm][25];

void add(int *head,node *edge,int &tot,int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].nxt=head[x];
    head[x]=tot;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++cok;
    st[++tp]=u;
    for(int i=head[u];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u])
            {
                add(trhead,tredge,trtot,++tx,u);
                add(trhead,tredge,trtot,u,tx);
                int x=0;
                do{
                    x=st[tp--];
                    add(trhead,tredge,trtot,tx,x);
                    add(trhead,tredge,trtot,x,tx);
                }while(x!=v);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
void dfs(int u)
{
    for(int i=trhead[u];i;i=tredge[i].nxt)
    {
        int v=tredge[i].to;
        if(!deep[v])
        {
            deep[v]=deep[u]+1;
            fa[v][0]=u;
            for(int j=1;j<=20;j++)
                fa[v][j]=fa[fa[v][j-1]][j-1];
            dfs(v);
        }
    }
}

int lca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(deep[fa[x][i]]>=deep[y]) x=fa[x][i];
    }
    if(x==y) return x;
    for(int i=20;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    }
    return fa[x][0];
}

int main()
{
    scanf("%d%d",&n,&m);
    tx=n;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(head,edge,tot,x,y);
        add(head,edge,tot,y,x);
    }

    tarjan(1);
    deep[1]=1;
    dfs(1);

    scanf("%d",&q);
    while(q--)
    {
        int u,v,t;
        scanf("%d%d",&u,&v);
        t=lca(u,v);
        printf("%d\n",(deep[u]+deep[v]-deep[t]*2)/2+1);
    }
}

例二 P4606 SDOI2018 战略游戏

圆方树上圆方果,圆方树下你和我。

圆方树后建虚树,欢乐多又多。

建出圆方树,然后建虚树。

维护虚树上父子点之间的圆点个数相加。

#include<bits/stdc++.h>
using namespace std;

const int maxn=2e5+5;

struct Edge
{
    int tot;
    int head[maxn];
    struct edgenode{int to,nxt;}edge[maxn*2];
    void add(int x,int y)
    {
        tot++;
        edge[tot].to=y;
        edge[tot].nxt=head[x];
        head[x]=tot;
    }
    void clr()
    {
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        tot=0;
    }
}Tr,G;

int n,m,cok,tp,tx;
int dfn[maxn],low[maxn],deep[maxn],f[maxn][25],st[maxn],len[maxn],wz[maxn],ed[maxn];

void tarjin(int u)
{
    dfn[u]=low[u]=++cok;
    st[++tp]=u;
    for(int i=G.head[u];i;i=G.edge[i].nxt)
    {
        int v=G.edge[i].to;
        if(!dfn[v])
        {
            tarjin(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u])
            {
                Tr.add(++tx,u);
                Tr.add(u,tx);
                int x=0;
                do
                {
                    x=st[tp--];
                    Tr.add(tx,x);
                    Tr.add(x,tx);
                }while(x!=v);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
void dfs(int u)
{
    len[u]+=(u<=n);
    wz[u]=++cok;
    for(int i=Tr.head[u];i;i=Tr.edge[i].nxt)
    {
        int v=Tr.edge[i].to;
        if(!deep[v])
        {
            deep[v]=deep[u]+1;
            f[v][0]=u;
            len[v]=len[u];
            for(int j=1;j<=20;j++) f[v][j]=f[f[v][j-1]][j-1];
            dfs(v);
        }
    }
    ed[u]=cok;
}
int Lca(int u,int v)
{
    if(deep[u]<deep[v]) swap(u,v);
    for(int i=20;i>=0;i--) if(deep[f[u][i]]>=deep[v]) u=f[u][i];
    if(u==v) return u;
    for(int i=20;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    return f[u][0];
}

int a[maxn];
bool vis[maxn];
bool cmp(int x,int y){return wz[x]<wz[y];}
bool isfa(int u,int v){return st[u]<st[v]&&ed[u]>=ed[v];}

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        memset(deep,0,sizeof(deep));
        Tr.clr();
        G.clr();
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(f,0,sizeof(f));
        memset(st,0,sizeof(st));
        memset(len,0,sizeof(len));
        memset(wz,0,sizeof(wz));
        memset(ed,0,sizeof(ed));
        cok=tp=tx=0;

        scanf("%d%d",&n,&m);
        tx=n;
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G.add(u,v);
            G.add(v,u);
        }

        tarjin(1);
        deep[1]=1;
        len[1]=1;
        cok=0;
        dfs(1);

        int p;
        scanf("%d",&p);
        while(p--)
        {
            int s;
            scanf("%d",&s);
            for(int i=1;i<=s;i++) scanf("%d",&a[i]),vis[a[i]]=1;
            sort(a+1,a+s+1,cmp);
            int sl=s;
            for(int i=1;i<s;i++)
            {
                int lca=Lca(a[i],a[i+1]);
                if(!vis[lca])
                {
                    vis[lca]=1;
                    a[++sl]=lca;
                }
            }
            sort(a+1,a+sl+1,cmp);
            int ans=-2*s;
            for(int i=1;i<=sl;i++)
            {
                int u=a[i],v=a[i%sl+1];
                ans+=len[u]+len[v]-2*len[Lca(u,v)];
            }
            if(Lca(a[1],a[sl])<=n) ans+=2;
            printf("%d\n",ans/2);
            for(int i=1;i<=sl;i++) vis[a[i]]=0;
        }
    }
}

推荐练习

P4630 APIO2018 铁人两项

鸣谢

「笔记」圆方树 - Luckyblock

标签:tx,int,笔记,edge,学习,圆方树,maxn,low,dfn
From: https://www.cnblogs.com/binbinbjl/p/17988877

相关文章

  • 全同态加密的硬件加速:让机器学习更懂隐私保护
    PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。问题:保护敏感数据企业机构间合作处理数据越来越频繁,通常使用云服务为数据共享保驾护航。保护数据隐私至关重要,特别是在处理个人可识别信息(PII......
  • 【跟着ChatGPT学深度学习】ChatGPT带我入门深度学习
    【跟着ChatGPT学深度学习】ChatGPT带我入门深度学习【跟着ChatGPT学深度学习】ChatGPT带我入门深度学习【跟着ChatGPT学深度学习】第一弹,入门深度学习。本次ChatGPT老师共教我三个知识点,分别是深度学习基础、深度学习的学习资源和深度学习需要掌握的技能和知识。最后,ChatGPT老......
  • 人工智能(第3版) 第二章—学习笔记
    人工智能(第3版)第二章—学习笔记2.0简介:智能系统中的搜索这一部分内容简单的列举了我们生活中出现的一些常见的搜索问题,并简单介绍了本章之后需要学习的状态分析图,生成——测试搜索范式,盲目搜索算法,贪心算法和回溯法等内容。2.1状态空间图状态空间图(state-spacegraph)是对......
  • WinDbg学习四(标准命令)
    命令都是实现在WinDBG内部的,执行这些命令时不需要加载任何扩展模块。大多数标准命令是一两个字符或者符号,只有version等少数命令除外。测试代码namespaceWinDbgConsoleSearch{internalclassProgram{privatestaticinti;......
  • OpenMP学习 第十一章 同步与OpenMP内存模型
    第十一章同步与OpenMP内存模型内存一致性模型OpenMP线程在共享内存中执行,共享内存是组中所有线程都可以访问的地址空间,其中存储着变量.使共享内存系统高效运行的唯一方法是允许线程保持一个临时的内存视图,该视图驻留在处理器和内存RAM之间的内存结构中.当线程通过共享内存......
  • WebAssembly入门笔记[2]:利用Memory传递数据
    利用灵活的“导入”和“导出”机制,WebAssembly与承载的JavaScript应用之间可以很便利地“互通有无”。《与JavaScript的交互》着重演示了如何利用函数的导入和导出实现功能的共享,接下来我们主要关注数据的传递或者共享。宗地来说,WebAssembly与宿主程序之间的数据传递主要有如下三......
  • Programming Abstractions in C阅读笔记:p254-p257
    《ProgrammingAbstractionsinC》学习第70天,p254-p257总结,总计4页。一、技术总结1.minimaxstrategy(极小化极大算法)p255,Thisidea--findingthepositionthatleavesyouropponentwiththeworstpossiblebestmove--iscalledtheminimaxstrategybecausethegoa......
  • 企业级微服务项目实战《学成在线》学习日志(二)
    下面正式开始开发!课程查询开发习惯从底层开始,所以就从DAO层(mapper层)开始写,再写service。先在content-service写个测试类,配置和包看黑马的去。介绍下以前学过的分页查询插件courseBaseMapper,实质上就是在sql语句上加上limit等语句,可以看下测试类的代码:@SpringBootTestpublic......
  • CS231N Assignment3 笔记(更新中)
    在这项作业中,将实现语言网络,并将其应用于COCO数据集上的图像标题。然后将训练生成对抗网络,生成与训练数据集相似的图像。最后,您将学习自我监督学习,自动学习无标签数据集的视觉表示。本作业的目标如下:1.理解并实现RNN和Transformer网络。将它们与CNN网络相结合,为图像添加标......
  • 动手学深度学习v2(李沐2021版),from d2l import torch as d2l报错
     点击查看代码%matplotlibinline#该项事实也无法运行fromd2limporttorchasd2l#此行报错如下所示点击查看代码---------------------------------------------------------------------------ImportErrorTraceback(mostrecentcal......