2021牛客暑期多校训练营6 J-Defend Your Country(无向图点双+思维)
生活随笔
收集整理的這篇文章主要介紹了
2021牛客暑期多校训练营6 J-Defend Your Country(无向图点双+思维)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
無向圖聯通分量
點u是割點,當且僅當
- 特判樹根:u為樹根,且u有多于1棵子樹
- u不為樹根,在遞歸樹上u存在子節點v,滿足:dfnu≤lowv\text{dfn}_u\leq \text{low}_vdfnu?≤lowv?
如上圖,v想走到u的組先必須經過u,那么u一定是割點。
邊(u,v)(u,v)(u,v)是割邊,當且僅當邊(u,v)(u,v)(u,v)為樹邊,且滿足dfnu<lowv?dfnv=lowv\text{dfn}_u< \text{low}_v\Leftrightarrow \text{dfn}_v= \text{low}_vdfnu?<lowv??dfnv?=lowv?
- 從v出發無法到達u以及u的祖先
- 非樹邊不可能是割邊,重邊不可能是割邊
J-Defend Your Country
Zechariah_2001題解
Alkaid~題解
下面結論詳細證明可以參考上面兩位大佬的題解
結論
-
對于nnn是偶數的情況,顯然不需要刪邊。
-
對于nnn是奇數的情況,最優方案一定是只刪除一個點連接的所有邊,只有這個點的貢獻會變負。刪去非割點顯然只用刪一個,刪掉割點必須保證刪除后連通塊點數都是偶數。
Code
#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=1000010; int h[N],e[N<<2],ne[N<<2],idx; void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} int n,m,a[N]; ll sum; int dfn[N],low[N],sz[N],timestamp; bool cut[N],no[N]; void tarjan(int u,int fa) {dfn[u]=low[u]=++timestamp;sz[u]=1;int chd=0;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(!dfn[v]){tarjan(v,u);sz[u]+=sz[v];low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]) {if(fa) cut[u]=1;// 根節點特判,v最多走到u走不到u上面去if(sz[v]&1) no[u]=1;}if(!fa) ++chd;// 特判根節點}else if(v!=fa) low[u]=min(low[u],dfn[v]);}if(chd>1) cut[u]=1; } void init() {idx=0;sum=0;timestamp=0;for(int i=1;i<=n;i++) h[i]=-1;for(int i=1;i<=n;i++) dfn[i]=low[i]=sz[i]=0;for(int i=1;i<=n;i++) no[i]=cut[i]=0; } int main() {int Tc=rd();while(Tc--){n=rd(),m=rd();init();for(int i=1;i<=n;i++) a[i]=rd(),sum+=a[i];while(m--){int u=rd(),v=rd();add(u,v),add(v,u);}if(n&1) {tarjan(1,0);int mn=0x3f3f3f3f;for(int i=1;i<=n;i++)if(!cut[i]||!no[i]) mn=min(mn,a[i]);printf("%lld\n",sum-2*mn);}else printf("%lld\n",sum);} }總結
以上是生活随笔為你收集整理的2021牛客暑期多校训练营6 J-Defend Your Country(无向图点双+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 七年磨一剑,小米澎湃OS何以“济沧海”
- 下一篇: 10月31日登场!华为nova 11 S