AmazingCounters.com

[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);
}

 

posted on 2017-09-13 17:40  ditoly  阅读(432)  评论(1编辑  收藏  举报