• [UOJ]#61. 【UR #5】怎样更有力气


    题面传送门

    做法:做法比较暴力。先按权值把每一天排序,从小到大做生成树,每一天我们先判这条链是否已经在同一个连通块(后面说怎么判),如果是就跳过,否则我们选出链的一个端点,然后找链上不与它在同一连通块的点,为了跳过同一连通块的点,我们用并查集维护每个点一直向祖先走,只走在同一连通块的点最远走到哪,合并连通块的时候我们启发式合并,顺便维护这个信息即可(利用这个信息,整条链是否属于同一个连通块也能判了),如果找到被限制条件限住的点,我们跳过,否则我们合并这两个连通块,链上与它不在同一连通块的点都走过之后,就把这个点从链上删掉从头做,我们每次考虑一个点对的时候要么是限制条件,要么是最后求出的生成树中的边,所以是O(n+p)的,加上启发式合并等复杂度,总时间复杂度大概是O(nlogn)级别的,常数较大。(另外貌似成为了UOJ上该题的代码最短)

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<map>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MN 300000
    #define K 19
    #define v(x,y) make_pair(min(x,y),max(x,y))
    struct work{int x,y,w,id;}w[MN+5];
    bool cmp(const work&a,const work&b){return a.w<b.w;}
    int fa[K][MN+5],f[MN+5],d[MN+5],c[MN+5];
    map<pair<int,int>,bool> mp[MN+5];
    vector<int> v[MN+5],vv[MN+5];
    int gf(int k){return f[k]?f[k]=gf(f[k]):k;}
    int lca(int x,int y)
    {
        if(d[x]<d[y])swap(x,y);
        int i=0,p=d[x]-d[y];
        for(;p;p>>=1,++i)if(p&1)x=fa[i][x];
        if(x==y)return x;
        for(i=K;i--;)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
        return fa[0][x];
    }
    void merge(int a,int b)
    {
        if(vv[a].size()>vv[b].size())swap(a,b);
        for(int i=0,x;i<vv[a].size();++i)
        {
            vv[c[x=vv[a][i]]=b].push_back(x);
            if(c[fa[0][x]]==b)f[x]=fa[0][x];
            for(int j=0;j<v[x].size();++j)if(c[v[x][j]]==b)f[v[x][j]]=x;
        }
    }
    int main()
    {
        int n,m,p,i,j,t,a,b;long long ans=0;
        n=read();m=read();p=read();
        for(d[1]=1,i=2;i<=n;++i)v[fa[0][i]=read()].push_back(i),d[i]=d[fa[0][i]]+1;
        for(j=1;j<K;++j)for(i=1;i<=n;++i)fa[j][i]=fa[j-1][fa[j-1][i]];
        for(i=1;i<=m;++i)w[i].x=read(),w[i].y=read(),w[i].w=read(),w[i].id=i;
        sort(w+1,w+m+1,cmp);
        while(p--)t=read(),a=read(),b=read(),mp[t][v(a,b)]=1;
        for(i=1;i<=n;++i)vv[i].push_back(c[i]=i);
        for(i=1;i<=m;++i)
        {
            j=lca(w[i].x,w[i].y);
            while(max(d[gf(w[i].x)],d[gf(w[i].y)])>d[j])
            {
                if(d[w[i].y]>d[w[i].x])swap(w[i].x,w[i].y);
                for(a=w[i].x;d[a]>=d[j];a=fa[0][a])
                {
                    if(c[a]==c[w[i].x]){a=gf(a);continue;}
                    if(mp[w[i].id][v(a,w[i].x)])continue;
                    ans+=w[i].w;merge(c[a],c[w[i].x]);
                }
                for(a=w[i].y;d[a]>=d[j];a=fa[0][a])
                {
                    if(c[a]==c[w[i].x]){a=gf(a);continue;}
                    if(mp[w[i].id][v(a,w[i].x)])continue;
                    ans+=w[i].w;merge(c[a],c[w[i].x]);
                }
                w[i].x=fa[0][w[i].x];
            }
        }
        printf("%lld",ans);
    }
  • 相关阅读:
    Socket原理与编程基础
    Hello cnblogs
    c# List 分页问题
    chrome下载Word失败问题
    前端时间Date显示问题踩坑
    Vue跳转同一界面多次,使用不同数据进行渲染
    Hadoop在Linux环境下的配置
    RabbitMQ下载安装
    Codeforces 527 C. Glass Carving
    python压缩、解压文件
  • 原文地址:https://www.cnblogs.com/ditoly/p/UOJ61.html
Copyright © 2020-2023  润新知