做法:做法比较暴力。先按权值把每一天排序,从小到大做生成树,每一天我们先判这条链是否已经在同一个连通块(后面说怎么判),如果是就跳过,否则我们选出链的一个端点,然后找链上不与它在同一连通块的点,为了跳过同一连通块的点,我们用并查集维护每个点一直向祖先走,只走在同一连通块的点最远走到哪,合并连通块的时候我们启发式合并,顺便维护这个信息即可(利用这个信息,整条链是否属于同一个连通块也能判了),如果找到被限制条件限住的点,我们跳过,否则我们合并这两个连通块,链上与它不在同一连通块的点都走过之后,就把这个点从链上删掉从头做,我们每次考虑一个点对的时候要么是限制条件,要么是最后求出的生成树中的边,所以是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); }