• 【BZOJ-3910】火车 倍增LCA + 并查集


    3910: 火车

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 262  Solved: 90
    [Submit][Status][Discuss]

    Description

    A 国有n 个城市,城市之间有一些双向道路相连,并且城市两两之间有唯一路径。现在有火车在城市 a,需要经过m 个城市。火车按照以下规则行驶:每次行驶到还没有经过的城市中在 m 个城市中最靠前的。现在小 A 想知道火车经过这m 个城市后所经过的道路数量。 

    Input

    第一行三个整数 n、m、a,表示城市数量、需要经过的城市数量,火车开始时所在位置。 
    接下来 n-1 行,每行两个整数 x和y,表示 x 和y之间有一条双向道路。 
    接下来一行 m 个整数,表示需要经过的城市。 

    Output

    一行一个整数,表示火车经过的道路数量。 

    Sample Input

    5 4 2
    1 2
    2 3
    3 4
    4 5
    4 3 1 5

    Sample Output

    9

    HINT

    N<=500000 ,M<=400000 

    Source

    Solution

    水题- -最多算个并查集的有趣应用

    很显然直接询问用LCA统计答案即可

    至于处理走过的路径,拿并查集维护一下,很简单的把起止点到LCA的点合并一下,询问的两个点如果属于一个集合显然走过

    Code

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    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*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 501000
    int n,m,a;
    struct EdgeNode{int to,next;}edge[maxn<<1];
    int head[maxn],cnt;
    void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    void insert(int u,int v) {add(u,v); add(v,u);}
    int deep[maxn],father[maxn][20],ffff[maxn];
    long long ans;
    void dfs(int now)
    {
        for (int i=1; i<=19; i++)
            if (deep[now]>=(1<<i))
                father[now][i]=father[father[now][i-1]][i-1];
            else
                break;
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=father[now][0])
                {
                    deep[edge[i].to]=deep[now]+1;
                    father[edge[i].to][0]=now;
                    dfs(edge[i].to);
                }
    }
    int LCA(int x,int y)
    {
        if (deep[x]<deep[y]) swap(x,y);
        int dd=deep[x]-deep[y];
        for (int i=0; (1<<i)<=dd; i++)
            if (dd&(1<<i)) x=father[x][i];
        for (int i=19; i>=0; i--)
            if (father[x][i]!=father[y][i])
                x=father[x][i],y=father[y][i];
        if (x==y) return x;
        return father[x][0];
    }
    int find(int x) {if (ffff[x]==x) return x; ffff[x]=find(ffff[x]); return ffff[x];}
    int ff1,ff2;
    int main()
    {
        n=read(),m=read(),a=read();
        for (int u,v,i=1; i<=n-1; i++)
            u=read(),v=read(),insert(u,v);
        dfs(1);
        for (int i=1; i<=n; i++) ffff[i]=i;
        for (int i=1; i<=m; i++)
            {
                int x=read();
                int fa=find(a),fx=find(x); 
                if (fa==fx) continue;
                int lca=LCA(a,x);
                ans+=deep[a]-deep[lca]+deep[x]-deep[lca];
                int ta=a,tx=x,flca; flca=find(lca);
                while (find(ta)!=flca) {ff1=find(ta); ffff[ff1]=flca; ta=father[ff1][0];}
                while (find(tx)!=flca) {ff2=find(tx); ffff[ff2]=flca; tx=father[ff2][0];}
                a=x;
            }
        cout<<ans;
        return 0;
    }

    电脑炸出奇怪的错误,所以写的比较鬼畜- -

  • 相关阅读:
    关于mysql创建数据库中字符集和排序规则的选择
    关于springboot中数据库连接池报错:testWhileIdle is true, validationQuery not set
    微软不允许以maven的方式直接下载该文件 (com.microsoft.sqlserver:sqljdbc4:jar:4.0),记录一下解决方案
    关于 idea 添加 web项目非 maven
    关于 tomcat版本和jdk版本的问题
    关于 jquery中的 只读两种属性(readonly,disabled),
    layui中如何给 表单中的input标签动态赋值,怎么获取父页面中的值
    pl/sql developer F5快捷键
    SQL中的left outer join,inner join,right outer join用法
    Aix下使用rman备份Oracle RAC数据库
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5595901.html
Copyright © 2020-2023  润新知