HDU 4297 One and One Story 树lca转rmq 并查集维护根节点环

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

题意:给定一个有向图,每个节点只有一条出边,现在两个人在两个节点沿着有向边走,按照题意输出相遇时两个人走的路径。
题解:这个有向图很特别,由于每个节点只有一条出边,所以如果形成一个环的话就只能有指向这个环的边,同时一个子图内最多存在一个环,tarjan搞掉环,
         建反图虚拟根节点转换成一棵树,根节点如果是环的环用带关系的并查集维护,然后lca->rmq,在线得到答案。
         每次lca->rmq总是一串代码…

Sure原创,转载请注明出处。

#pragma comment (linker , "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <cmath>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
#define MAX(a , b) ((a) > (b) ? (a) : (b))
using namespace std;
const int maxn = 500002;
struct node
{
    int v;
    int next;
}edge[maxn << 1];
int up[maxn],down[maxn],head[maxn],father[maxn],dis[maxn];
int dfn[maxn],low[maxn],s[maxn],belong[maxn],cnt[maxn],indegree[maxn];
int E[maxn << 1],D[maxn << 1],bj[maxn],dep[maxn],dp[maxn << 1][20];
bool vis[maxn],instack[maxn];
int m,n,idx,tmpdfn,tot,top,bound;

void init()
{
    memset(head,-1,sizeof(head));
    memset(cnt,0,sizeof(cnt));
    memset(vis,false,sizeof(vis));
    memset(instack,false,sizeof(instack));
    idx = tmpdfn = 0;
    tot = 1;
    return;
}

inline void in(int &a)
{
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9');
    a = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9')
    {
        a = a * 10 + ch - '0';
    }
    return;
}

void swap(int &a,int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
    return;
}

int find(int u)
{
    if(u == father[u]) return father[u];
    int tmp = father[u];
    father[u] = find(tmp);
    dis[u] += dis[tmp];
    return father[u];
}

void addedge(int u,int v)
{
    edge[idx].v = v;
    edge[idx].next = head[u];
    head[u] = idx++;
    return;
}

void read()
{
    for(int i=1;i<=n;i++)
    {
        father[i] = i;
        in(down[i]);
        addedge(i , down[i]);
    }
    return;
}

void tarjan(int st)
{
    dfn[st] = low[st] = tmpdfn++;
    vis[st] = instack[st] = true;
    s[top++] = st;
    for(int i=head[st];i != -1;i=edge[i].next)
    {
        if(vis[edge[i].v] == false)
        {
            tarjan(edge[i].v);
            low[st] = MIN(low[st] , low[edge[i].v]);
        }
        else if(instack[edge[i].v])
        {
            low[st] = MIN(low[st] , dfn[edge[i].v]);
        }
    }
    if(dfn[st] == low[st])
    {
        int u;
        do
        {
            u = s[--top];
            instack[u] = false;
            belong[u] = tot;
            cnt[tot]++;
        }while(u != st);
        tot++;
    }
    return;
}

void reset()
{
    memset(head,-1,sizeof(head));
    memset(up,-1,sizeof(up));
    memset(dis,0,sizeof(dis));
    memset(indegree,0,sizeof(indegree));
    memset(dep,0,sizeof(dep));
    idx = top = 0;
    return;
}

void make()
{
    for(int i=1;i<=n;i++)
    {
        if(vis[i] == false)
        {
            top = 0;
            tarjan(i);
        }
    }
    reset();
    for(int i=1;i<=n;i++)
    {
        int u = belong[down[i]];
        int v = belong[i];
        if(u != v)
        {
            addedge(u,v);
            indegree[v]++;
            if(cnt[u] > 1)
            {
                up[v] = down[i];
            }
        }
        else
        {
            int x = find(down[i]);
            int y = find(i);
            if(x != y)
            {
                father[y] = x;
                dis[y] = dis[down[i]] + 1;
            }
        }
    }
    for(int i=1;i<tot;i++)
    {
        if(indegree[i] == 0)
        {
            addedge(0,i);
        }
    }
    return;
}

void dfs(int st,int h)
{
    dep[st] = h;
    E[++top] = st;
    D[top] = h;
    bj[st] = top;
    for(int i=head[st];i != -1;i=edge[i].next)
    {
        if(up[edge[i].v] == -1)
        {
            up[edge[i].v] = up[st];
        }
        dfs(edge[i].v , h+1);
        E[++top] = st;
        D[top] = h;
    }
    return;
}

void init_rmq()
{
    for(int i=1;i<=top;i++)
    {
        dp[i][0] = i;
    }
    for(int j=1;j<=bound;j++)
    {
        for(int i=1;i + (1 << j) - 1 <= top;i++)
        {
            if(D[dp[i][j-1]] < D[dp[i + (1 << (j-1))][j-1]])
            {
                dp[i][j] = dp[i][j-1];
            }
            else
            {
                dp[i][j] = dp[i + (1 << (j-1))][j-1];
            }
        }
    }
    return;
}

int askrmq(int l,int r)
{
    if(l > r) swap(l , r);
    int d = log((double)(r - l + 1)) / log(2.0);
    int wei = -1;
    if(D[dp[l][d]] < D[dp[r - (1 << d) + 1][d]])
    {
        wei = dp[l][d];
    }
    else
    {
        wei = dp[r - (1 << d) + 1][d];
    }
    return E[wei];
}

void solve()
{
    dfs(0,0);
    bound = log((double)(top + 1)) / log(2.0);
    init_rmq();
    int u,v;
    while(m--)
    {
        in(u),in(v);
        if(u == v)
        {
            puts("0 0");
            continue;
        }
        int x = belong[u];
        int y = belong[v];
        int lca = askrmq(bj[x] , bj[y]);
        if(lca == 0)
        {
            puts("-1 -1");
            continue;
        }
        else if(cnt[lca] == 1)
        {
            printf("%d %d\n",dep[x] - dep[lca],dep[y] - dep[lca]);
            continue;
        }
        int dx,dy,dxy,dyx;
        if(x == y)
        {
            dx = dy = 0;
            find(u),find(v);
            if(dis[u] < dis[v])
            {
                dxy = cnt[x] + dis[u] - dis[v];
                dyx = dis[v] - dis[u];
            }
            else
            {
                dxy = dis[u] - dis[v];
                dyx = cnt[x] - dxy;
            }
        }
        else
        {
            dx = dep[x] - dep[lca];
            dy = dep[y] - dep[lca];
            if(cnt[lca] == 1)
            {
                dxy = dyx = 0;
            }
            else
            {
                u = (up[x] == -1) ? u : up[x];
                v = (up[y] == -1) ? v : up[y];
                find(u),find(v);
                if(dis[u] < dis[v])
                {
                    dxy = cnt[lca] + dis[u] - dis[v];
                    dyx = dis[v] - dis[u];
                }
                else
                {
                    dxy = dis[u] - dis[v];
                    dyx = cnt[lca] - dxy;
                }
            }
        }
        if(MAX(dx+dxy , dy) < MAX(dx , dy+dyx))
        {
            printf("%d %d\n",dx+dxy , dy);
        }
        else if(MAX(dx+dxy , dy) > MAX(dx , dy+dyx))
        {
            printf("%d %d\n",dx , dy+dyx);
        }
        else
        {
            if(MIN(dx+dxy , dy) < MIN(dx , dy+dyx))
            {
                printf("%d %d\n",dx+dxy , dy);
            }
            else if(MIN(dx+dxy , dy) > MIN(dx , dy+dyx))
            {
                printf("%d %d\n",dx , dy+dyx);
            }
            else
            {
                printf("%d %d\n",MAX(dx+dxy , dy),MIN(dx , dy+dyx));
            }
        }
    }
    return;
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        init();
        read();
        make();
        solve();
    }
    return 0;
}

飞书文档API深度使用指南:如何用n8n社区节点绕过HTTP Request的复杂配置 本文详细解析了如何利用n8n社区节点简化飞书文档API的集成过程,绕过复杂的HTTP Request配置。通过n8n-feishu-lite社区节点,开发者可以轻松实现飞书文档的创建、编辑和查询操作,大幅提升自动化工作流的效率。文章还提供了高级应用场景和性能优化建议,帮助开发者更好地利用飞书开放平台的API功能。 阅读详情

相关推荐

Qt 5.15.2静态编译避坑实录:MinGW 32位版从源码到Creator配置的全流程踩坑总结

本文详细介绍了Qt 5.15.2 MinGW 32位版本的静态编译全流程,包括境准备、配置参数优化、编译过程监控及安装后配置。重点解决了静态编译中的常见问题,如参数顺序敏感、路径引号问题等,并提供了性能对比实测数据,帮助开发者高效完成静态编译。

weixin_26749245的博客 249

hdu 4297 One and One Story(维护森林中的LCA)

题意:有n个房间,每个房间有且只有一条出边指向另一个房间,现给出两个人在两个房间,问让他俩汇合要走的最少的路径数 解法:观察图的形态,由于n个点n条边,且每个点出度为1,因此可以认为是一个森林,森林里每棵都加了一条边形成了一个,且根节点(可以认为缩点后没有出边,即没有父节点)。 显然两点属于不同的时候不可达;因为图的特殊性,因此没有用强连通做,而是用了并查集,也便于给上每个点标

新博客地址:sensirly.github.io 2475

我用两个月时间,终于把CSDN付费资源项目玩明白了!

关于项目的定位,这是一个知识付费项目,根据市场研究机构的数据显示,到2023年,全球知识付费市场规模将达到2000亿美元,所以说知识付费的前景是十分广阔的,当下互联网时代信息大爆炸,80后、90后、00后群体对知识付费的认可度也大幅提升,同时这群作为知识付费的主流人群已经具备了更强的消费能力,而且对于知识付费的需求更高。目前整个知识付费领域仍然在发展起步的初期,尽快在知识付费领域布局可以帮助我们在这波红利中获得一份不错的收益。而且个人认为,

白话机器学习 2万+

LCA HDU 4297 One and One Story

One and One Story Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 760    Accepted Submission(s): 353 Problem Description     Have

We Can 756

HDU 4297-One and One Story解题报告

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4297 这道题所给的图是一个森林,每一个子图都必有一个(因为总边数为n),可以把当做这棵根节点,那么如果两个点不在一棵上,一定互相不可达,如果在一棵上,如果两个点在同一棵子上,那么一起到的点就是LCA,所以要维护森林的LCA,如果不在同一棵子上,则要到各自的根节点,然后沿着方向...

weixin_30653097的博客 359

hdu-4297

//一个规律题,直接找规律就好了; //代码如下:   #include #include __int64 find(__int64 x) { __int64 sum=(x-4)/2,k; if(x<=5)return 0; k=sqrt(x); if(k*k>x)--k; if(k&1)++sum; return sum; } int main() { int cas; _

Lazier’s blog 753

hdu 4297 One and One Story (维护森林中的LCA)

题意:有n个房间,每个房间有且只有一条出边指向另一个房间,现给出两个人在两个房间,问让他俩汇合要走的最少的路径数 解法:观察图的形态,由于n个点n条边,且每个点出度为1,因此可以认为是一个森林,森林里每棵都加了一条边形成了一个,且根节点(可以认为缩点后没有出边,即没有父节点)。 显然两点属于不同的时候不可达;因为图的特殊性,因此没有用强连通做,而是用了并查集,也便于给上每个点标

liuzhushiqiang的专栏 1451

hdu One and One Story tarjan缩点+rmq+LCA

http://acm.hdu.edu.cn/showproblem.php?pid=4297 题意: 给出n个点的有向图,每个点的出度均为1.有m个询问,每个询问两个数(u,v),表示两个人一个在u一个在v。 对于每个询问,请你选择一个点P使得u、v均能到达P。设u到达P需要A步,v到达P需要B步。求一个P使得max(A,B)最小? 若答案不唯一,输出min(A,B)最小的;若答案还不唯一...

weixin_30569153的博客 98

HDU 4296 Buildings 公式证明贪心的正确性

题意:有n(1          现在想安排一种摆放方案使得max(PDVi)最小。 题解:现在考虑相邻的两块i j,设上方sigama(wi)  = sum,i 在 j上方时分别得到PDVi = sum - si,PDVj = sum + wi - sj,同理得到j在i上方时          PDVjj = sum - sj,PDVii = sum + wj - si,若i在j上方始终优

Uhh, call me zacky NOW!!! 1万+

HDU 4275 Color the Tree 的不重复染色 求的中心+hash

题意:给定n(n 题解:这题完全是看人家的代码看懂的唉…          首先找到的中心(不是重心),中心的定义是的直径的中点,如果直径上节点个数是偶数,那么在中间建立一个新的节点。          然后从中心dfs,对于每一棵子得到相应的hash值(hash方法:hash[i]= A * (hash[j1]*B)^hash[j2]*B.....^hash[jn]*C%D;(顺序执

Uhh, call me zacky NOW!!! 2477

HDU 4271 Find Black Hand 求字串编辑距离dp

题意:给定串长          母串中的substring,求最小的编辑距离,和对应字典序最小的字串。 题解:比赛的时候看了一眼,substring看着有点晃,就搞别的了,还是自己太弱最后没有时间仔细想想这个题目。          对于两个串的编辑距离可以用O(n*m)的复杂度来搞,对于字串只需要做一点修改即可,具体见代码注释。          对于长度为len的串,要想成为母串的s

Uhh, call me zacky NOW!!! 2184

HDU 4411 Arrest 最小费用流

题意:有n(0           i - 1 点,到达一个点的时候可以选择不占领,问最后 题解:floyd之后建图,因为要保证所有的点依次占领,所以每个点拆点流量为1费用为-inf(保证所有点都被占领),然后从j(j 费用为map[ j ][ i ]         (因为点的访问是要按照顺序的),然后从原点ss到i建容量为inf费用为map[0][i]的边,同理从i+n(i 拆的出边点)

Uhh, call me zacky NOW!!! 2047

HDU 4415 Assassin’s Creed 苦逼的贪心

题意:一个人有把耐久度为m(1          的刀,敌人死后留下的刀可以杀死bi个敌人而不费耐久度,问能最多杀多少人,且杀最多人的时候耐久度消耗最小的值。 题解:将敌人分成两类,一类是bi为0,一类不为0,只要能杀死一个bi不为0敌人就能得到所有的bi。          分两种情况:1 只杀bi=0的敌人,这种情况排序从ai小的开始杀即可;

Uhh, call me zacky NOW!!! 1290

HDU 4281 Judges' response dp+tsp极致

题意:给定n(n          任意两点间的距离是ceil(sqrt((xi - xj) ^ 2 + (yi - yj) ^ 2))。          问题1:最少需要多少个裁判能完成所有选手的检查任务;          问题2(和问题1没有关系,只是在问题1有解的情况下):安排裁判数量任意多,求完成任务的裁判走的最短时间和。 题解:对于问题1:考虑dp[i]表示i状态下完成任务的

Uhh, call me zacky NOW!!! 1205

HDU 4414 Finding crosses 暴力枚举

题意:在#o组成的n*n(3 题解:枚举每一个#假设其为一个合法十字架的中心位置即可。 Sure原创,载请注明出处。 #include #include using namespace std; const int maxn = 52; const int move[4][2] = {{-1,0},{0,1},{1,0},{0,-1}}; char map[maxn][ma

Uhh, call me zacky NOW!!! 1171

HDU 4274 Spy's Work 形dfs

题意:给定一棵节点为n(n           即u)w代表以u节点为根节点的员工权值和)w,问给定的m(m 题解:维护每棵子的最大最小可能值(或者确定值,如果是 "=" 的话)。 Sure原创,载请注明出处。 #include #include #include #define MIN(a , b) ((a) < (b) ? (a) : (b)) #define MAX

Uhh, call me zacky NOW!!! 1119

HDU 4272 LianLianKan 记忆化搜索

题意:长度为n(n 题解:dp[i][j]表示当前栈顶10个元素的状态为 i 栈顶深度为 j 时是否可行(1代表当前元素未选,0代表已选),移很直观但dp方程不好写,记忆化dfs实现。          为什么是10个呢,可以想下,从开始的状态最坏的情况是每次栈顶的元素都取最远的,进行5次之后得到的状态是1010101010,未选择的元素恰好为5          总个数为10,所以需要记

Uhh, call me zacky NOW!!! 1104

HDU 4293 Groups 拓扑排序

题意:有n(n 题解:看这个题想应该是dp,若菜比赛的时候没想出来dp怎么搞,无奈只好yy了一个拓扑排序,开始因为没有处理好说相同话的情况wa了一次。          具体建图方法:所有合法的话,按照x升序y降序排列,枚举i j如果两个人说的话不矛盾建边,这里需要注意的是相同的话最多出现n - x - y次,          多余的直接删除,因为多余的一定是假话。然后拓扑排序找最长路。

Uhh, call me zacky NOW!!! 958

HDU 4409 Family Name List 简单操作

题意:按照题目描述给一棵(家族谱,节点n           c name name输出两个人的lca是多少(lca不能是name本身)。 题解:vector存储节点数这样很容易排序,然后保存下L的序列,sum[ i ]表示当前 i 节点的直接儿子节点的个数,rmq处理出lca。 Sure原创,载请注明出处。 #pragma comment (linker , "/ST

Uhh, call me zacky NOW!!! 907
上一篇: POJ 2484 A Funny Game 简单博弈
下一篇: HDU 4288 Coder 线段树维护区间%5的和
zacky_su
博客等级 码龄14年 12粉丝 90原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值