P6033 Ryoku 的探索 (基环树)
题解:
图为一个基环树。
dfs找到环,对于环上的每一个点u, 确定与它连接的具有最小美观度的边的长度w, 把这个w值更新到与它连接的其他非环上点(minval[]数组),则u和与它连接的其他非环上点的答案即为所有边长度只和减去minval[i]。
Code:
1 #include <bits/stdc++.h> 2 # define LL long long 3 using namespace std; 4 5 const int maxn=1000000+10; 6 const int INF=0x7fffffff; 7 struct Edge{ 8 int v,next,w,p; 9 }e[maxn<<1]; 10 int head[maxn]; 11 int en; 12 13 int n; 14 int incycle[maxn]; 15 int instack[maxn]; 16 stack<int> stk; 17 bool hasfind; 18 int minval[maxn]; 19 20 21 void add(int from, int to, int w, int p){ 22 e[en].v=to; 23 e[en].next=head[from]; 24 e[en].w=w; 25 e[en].p=p; 26 head[from]=en; 27 ++en; 28 } 29 30 void dfs(int u, int pre){ 31 if(hasfind) return; 32 if(instack[u]==1){ 33 while(stk.top()!=u){ 34 int t=stk.top(); 35 stk.pop(); 36 incycle[t]=1; 37 instack[t]=0; 38 } 39 stk.pop(); 40 instack[u]=0; 41 incycle[u]=1; 42 hasfind=true; 43 return; 44 } 45 instack[u]=1; 46 stk.push(u); 47 for(int i=head[u];i!=-1;i=e[i].next){ 48 int v=e[i].v; 49 if(v==pre) continue; 50 dfs(v,u); 51 } 52 stk.pop(); 53 instack[u]=0; 54 } 55 56 void setvalue(int u, int val){ 57 minval[u]=val; 58 for(int i=head[u];i!=-1;i=e[i].next){ 59 int to=e[i].v; 60 if(incycle[to]==0 && minval[to]==-1){ 61 setvalue(to,val); 62 } 63 } 64 } 65 66 int main(){ 67 memset(head,-1,sizeof(head)); 68 memset(minval,-1,sizeof(minval)); 69 scanf("%d", &n); 70 LL total=0; 71 for(int i=1;i<=n;++i){ 72 int a,b,c,d; 73 scanf("%d %d %d %d", &a, &b, &c, &d); 74 total+=c; 75 add(a,b,c,d); 76 add(b,a,c,d); 77 } 78 hasfind=false; 79 dfs(1,0); 80 81 for(int i=1;i<=n;++i){ 82 if(incycle[i]==1){ 83 int minp=INF; 84 int minw=0; 85 for(int j=head[i];j!=-1;j=e[j].next){ 86 int to=e[j].v; 87 if(incycle[to]==1){ 88 if(e[j].p<minp){ 89 minp=e[j].p; 90 minw=e[j].w; 91 } 92 } 93 } 94 setvalue(i,minw); 95 } 96 } 97 98 for(int i=1;i<=n;++i){ 99 printf("%lld\n", total-minval[i]); 100 } 101 return 0; 102 }