洛谷 三月月赛 C
呵呵呵呵,这个sb题做了好久,然并卵,还是不对。
挖坑++
然而我感觉我做的对了,偷瞄了一下题解应该没什么问题。
这个题有n个点,n条边,所以是个基环树(我也不知道是不是这个名)
要每个点有联通,就是一个n个点的环,要是答案最小,那么我们就要保留下一些最大的链
现在我们考虑,因为一个点只有一个入度(n-1条边的话是一个严格从根节点单向向外的树),现在多了一个边,所以多了形成一个环
那先现在这个东西(基环树)就是一个环外面挂着一些严格向外延展的子树。
所以先考虑子树,对于每一个节点,贪心的保留一个权值最大的边连的儿子保留,其他的切掉(这里说的切掉是指重建),(这一步做完之后出来的东西就类似于树链剖分出来的重链)
再来考虑环,与环相连的子树,选择切掉,那么环是不用动的,选择不切,那么在环上对应的下条边是要切掉的。(这里打一个标记,判断切没切,然后,没切的话要找环上最小的边切开)
需要注意的是,可以不止一个基环树233333
1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 1LL<<60 5 using namespace std; 6 inline LL ra() 7 { 8 LL x=0,f=1; char ch=getchar(); 9 while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} 10 while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} 11 return x*f; 12 } 13 struct edge{ 14 int to,next; LL v; 15 }e[N]; 16 int head[N],cnt,n,start,d[N]; 17 int top,ind,q[N],low[N],dfn[N],size[N],num,belong[N]; 18 LL ans,sum,f[N],del,cst[N]; 19 bool vis[N],cut,inq[N],can[N]; 20 void insert(int x, int y, LL v) 21 { 22 e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].v=v; head[x]=cnt; 23 } 24 void tarjan(int x) 25 { 26 dfn[x]=low[x]=++ind; 27 q[++top]=x; inq[x]=1; 28 for (int i=head[x];i;i=e[i].next) 29 if (!dfn[e[i].to]) 30 { 31 tarjan(e[i].to); 32 low[x]=min(low[e[i].to],low[x]); 33 } 34 else if (inq[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); 35 if (low[x]==dfn[x]) 36 { 37 ++num; 38 int now=-1; 39 while (now!=x) 40 { 41 now=q[top--]; 42 belong[now]=num; 43 size[num]++; 44 inq[now]=0; 45 } 46 } 47 } 48 void get_cost(int x) 49 { 50 can[x]=1; 51 for (int i=head[x];i;i=e[i].next) 52 { 53 if (vis[e[i].to]) cst[x]=e[i].v; 54 if (e[i].to==start || !vis[e[i].to]) continue; 55 get_cost(e[i].to); 56 } 57 } 58 void solve_son(int x) 59 { 60 LL son_sum=0,son_mx=0; 61 for (int i=head[x];i;i=e[i].next) 62 { 63 son_sum+=e[i].v,son_mx=max(son_mx,e[i].v); 64 f[x]+=f[e[i].to]; 65 solve_son(e[i].to); 66 } 67 f[x]+=son_sum-son_mx; 68 } 69 void dfs(int x) 70 { 71 LL son_del=-inf; can[x]=1; 72 for (int i=head[x];i;i=e[i].next) 73 { 74 son_del=max(son_del,-cst[x]); 75 if (e[i].to==start) continue; 76 if (vis[e[i].to]) dfs(e[i].to); 77 else 78 { 79 solve_son(e[i].to); 80 ans+=f[e[i].to]+e[i].v; 81 son_del=max(son_del,e[i].v-cst[x]); 82 } 83 } 84 if (son_del>0) cut=1,ans-=son_del; else del=max(del,son_del); 85 } 86 int main() 87 { 88 n=ra(); 89 for (int i=1; i<=n; i++) 90 { 91 int x=ra(); 92 LL v=(LL)ra(); 93 if (x==i) ans+=v; else insert(x,i,v); 94 } 95 for (int i=1; i<=n; i++) 96 if (!dfn[i]) tarjan(i); 97 int hehe=0; 98 bool flag=0; 99 for (int i=1; i<=n; i++) 100 if (size[belong[i]]>1) 101 { 102 if (hehe && hehe!=belong[i]) flag=1; 103 hehe=belong[i]; 104 vis[i]=1; 105 } 106 for (int i=1; i<=n; i++) 107 if (!vis[i]) {flag=1; break;} 108 if (!flag) 109 { 110 cout<<"0"<<endl; 111 return 0; 112 } 113 for (int i=1; i<=n; i++) 114 if (vis[i] && !can[i]) 115 { 116 start=i; 117 get_cost(i); 118 } 119 memset(can,0,sizeof(can)); 120 for (int i=1; i<=n; i++) 121 if (vis[i] && !can[i]) 122 { 123 cut=0; del=-inf; 124 start=i; dfs(i); 125 if (!cut) ans-=del; 126 } 127 // for (int i=1; i<=n; i++) printf("%d ",f[i]); 128 cout<<ans<<endl; 129 return 0; 130 }