1977: [BeiJing2010組隊]次小生成樹 Tree
阿新 • • 發佈:2018-07-20
包含 += void href efi 題解 希望 sin num
Submit: 3853 Solved: 1104
[Submit][Status][Discuss]
這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
題解:和cf的一道題比較類似 首先跑一個MST 對於這個樹做樹鏈剖分 枚舉不在這個樹上的邊找嚴格小於這條邊的最大邊權值 然後求ans
#include <bits/stdc++.h> #define ll long long const int MAXN=1e5+10; const int maxn=3e5+10; const int inf=1e9+20; using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar(); return f*x; } vector<pair<int,int> >vec[MAXN]; typedef struct Edge{ int u,v,vul;bool flag; friend bool operator<(Edge aa,Edge bb){return aa.vul<bb.vul;} }Edge; Edge edge[maxn]; int n,m,f[MAXN]; int find1(int x){ if(f[x]==x)return x; else return f[x]=find1(f[x]); } int key[MAXN],fa[MAXN],dep[MAXN],num[MAXN],son[MAXN]; void dfs(int v,int pre,int deep){ dep[v]=deep+1;num[v]=1;fa[v]=pre; for(int i=0;i<vec[v].size();i++){ int u=vec[v][i].first; if(u!=pre){ key[u]=vec[v][i].second; dfs(u,v,deep+1); num[v]+=num[u]; if(son[v]==-1||num[son[v]]<num[u])son[v]=u; } } } int tp[MAXN],cnt,p[MAXN],fp[MAXN]; void dfs1(int v,int td){ p[v]=++cnt;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1)dfs1(son[v],td); for(int i=0;i<vec[v].size();i++){ if(vec[v][i].first!=fa[v]&&vec[v][i].first!=son[v])dfs1(vec[v][i].first,vec[v][i].first); } } int maxx[MAXN<<2],maxx1[MAXN<<2]; void up(int x){ maxx[x]=max(maxx[x<<1],maxx[x<<1|1]); maxx1[x]=maxx1[x<<1]; if(maxx[x<<1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx[x<<1]); if(maxx[x<<1|1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx[x<<1|1]); if(maxx1[x<<1|1]!=maxx[x])maxx1[x]=max(maxx1[x],maxx1[x<<1|1]); } void built(int rt,int l,int r){ if(l==r){maxx[rt]=key[fp[l]];maxx1[rt]=-1;return ;} int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); up(rt); } int ans1; void querty(int rt,int l,int r,int ql,int qr,int vul){ if(ql<=l&&r<=qr){ if(maxx[rt]==vul)ans1=max(ans1,maxx1[rt]); else ans1=max(ans1,maxx[rt]); return ; } int mid=(l+r)>>1; if(ql<=mid)querty(rt<<1,l,mid,ql,qr,vul); if(qr>mid)querty(rt<<1|1,mid+1,r,ql,qr,vul); } int slove(int u,int v,int t){ int uu=tp[u];int vv=tp[v]; ans1=-1*inf; while(uu!=vv){ if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v); querty(1,1,n,p[uu],p[u],t); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v])swap(u,v); if(u!=v)querty(1,1,n,p[son[u]],p[v],t); return ans1; } int main(){ n=read();m=read();int u,v,vul; for(int i=1;i<=m;i++)edge[i].u=read(),edge[i].v=read(),edge[i].vul=read(); for(int i=1;i<=n;i++)f[i]=i,son[i]=-1; sort(edge+1,edge+m+1);ll ans=0; for(int i=1;i<=m;i++){ int t1=find1(edge[i].u); int t2=find1(edge[i].v); if(t1==t2)continue; ans+=edge[i].vul; f[t1]=t2;vec[edge[i].u].push_back(make_pair(edge[i].v,edge[i].vul)); vec[edge[i].v].push_back(make_pair(edge[i].u,edge[i].vul));edge[i].flag=1; } //cout<<ans<<endl; dfs(1,0,0);dfs1(1,1);built(1,1,n); // cout<<"sb"<<endl; ll ans2=1e18; for(int i=1;i<=m;i++){ if(edge[i].flag)continue; vul=slove(edge[i].u,edge[i].v,edge[i].vul); if(vul<0)continue; ans2=min(ans2,ans-vul+1ll*edge[i].vul); } printf("%lld\n",ans2); return 0; }
1977: [BeiJing2010組隊]次小生成樹 Tree
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3853 Solved: 1104
[Submit][Status][Discuss]
Description
小 C 最近學了很多最小生成樹的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正當小 C 洋洋得意之時,小 P 又來潑小 C 冷水了。小 P 說,讓小 C 求出一個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說: 如果最小生成樹選擇的邊集是 EM,嚴格次小生成樹選擇的邊集是 ES,那麽需要滿足:(value(e) 表示邊 e的權值)
Input
第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z 表示,點 x 和點y之間有一條邊,邊的權值為z。
Output
包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(數據保證必定存在嚴格次小生成樹)
Sample Input
5 61 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
Sample Output
11HINT
數據中無向圖無自環; 50% 的數據N≤2 000 M≤3 000; 80% 的數據N≤50 000 M≤100 000; 100% 的數據N≤100 000 M≤300 000 ,邊權值非負且不超過 10^9 。
1977: [BeiJing2010組隊]次小生成樹 Tree