CF 609E 树上的倍增

  1 /*
  2   Source   :CF 609E
  3   Problem  :给定n个顶点,m条边的图,对于一条边,求包含这条边的最小生成树
  4   Solution :先求出MST,然后对于一条给定的边,对应的最小生成树为MST中去掉u,v路径上的最大的边,然后加上当前的边
  5             对于后面的问题,求解u,v路径上的最大边,可用树上的倍增法解决。
  6   Date     :2018-08-16-20.46
  7 */
  8 
  9 #include <bits/stdc++.h>
 10 using namespace std;
 11 
 12 typedef long long LL;
 13 const int MAXN = 100005;
 14 const LL MOD7 = 1e9+7;
 15 
 16 struct E
 17 {
 18     int u,v,c;
 19     int idx;
 20 }e[2*MAXN];
 21 LL Ans[2*MAXN];
 22 
 23 int cmp(E a,E b)
 24 {
 25     return a.c<b.c;
 26 }
 27 
 28 struct Edge
 29 {
 30     int u,v,c;
 31     int next;
 32 }edge[4*MAXN];
 33 int head[2*MAXN];
 34 int cnt;
 35 
 36 
 37 int dep[2*MAXN];
 38 int f[2*MAXN][30];
 39 int dp[2*MAXN][30];
 40 int n,m;
 41 
 42 
 43 void init()
 44 {
 45     memset(head,-1,sizeof(head));
 46     cnt=0;
 47 }
 48 
 49 void addEdge(int u,int v,int c)
 50 {
 51     edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;
 52 }
 53 
 54 void dfs(int u,int pre,int c)
 55 {
 56     f[u][0]=pre;
 57     dp[u][0]=c;
 58     for (int i=head[u];i!=-1;i=edge[i].next)
 59     {
 60         int v=edge[i].v;
 61         if (v==pre) continue;
 62         dep[v]=dep[u]+1;
 63         dfs(v,u,edge[i].c);
 64     }
 65 }
 66 
 67 void BZ()
 68 {
 69     for (int j=1;j<30;++j)
 70     {
 71         for (int i=1;i<=n;++i)
 72         {
 73             if (f[i][j-1])
 74             {
 75                 f[i][j]=f[f[i][j-1]][j-1];
 76                 dp[i][j] = max(dp[i][j-1], dp[f[i][j-1]][j-1]);
 77             }
 78         }
 79     }
 80 }
 81 
 82 int query(int u,int v)
 83 {
 84     if (dep[u]<dep[v]) swap(u,v);
 85     int ans=0;
 86     int delta=dep[u]-dep[v];
 87     for (int i=0;i<30;++i)
 88     {
 89         if (delta&(1<<i))
 90         {
 91             ans=max(ans,dp[u][i]);
 92             u=f[u][i];
 93         }
 94     }
 95     if (u==v) return ans;
 96     for (int i=29;i>=0;--i)
 97     {
 98         if (f[u][i]!=f[v][i])
 99         {
100             ans=max(ans, dp[u][i]);
101             ans=max(ans, dp[v][i]);
102             u=f[u][i];
103             v=f[v][i];
104         }
105     }
106     ans=max(ans, dp[u][0]);
107     ans=max(ans, dp[v][0]);
108     return ans;
109 }
110 
111 struct Union_set
112 {
113     int f[2*MAXN];
114     void init(int n)
115     {
116         for (int i=1;i<=n;++i) f[i]=i;
117     }
118     int find(int x)
119     {
120         if (x==f[x]) return x;
121         return f[x]=find(f[x]);
122     }
123     bool Union(int x,int y)
124     {
125         int fx=find(x);
126         int fy=find(y);
127         if (fx==fy) return false;
128         f[fx]=fy;
129         return true;
130     }
131 }union_set;
132 
133 int main()
134 {
135 #ifndef ONLINE_JUDGE
136     freopen("test.txt","r",stdin);
137 #endif // ONLINE_JUDGE
138     while (scanf("%d%d",&n,&m)!=-1)
139     {
140         init();
141         int u,v,c;
142         for (int i=1;i<=m;++i)
143         {
144             scanf("%d%d%d",&u,&v,&c);
145             e[i].u=u;e[i].v=v;e[i].c=c;
146             e[i].idx=i;
147         }
148         sort(e+1,e+1+m,cmp);
149         union_set.init(n);
150         LL ans=0;
151         for (int i=1;i<=m;++i)
152         {
153             u=e[i].u;
154             v=e[i].v;
155             if (union_set.Union(u,v))
156             {
157                 ans+=e[i].c;
158                 addEdge(u,v,e[i].c);
159                 addEdge(v,u,e[i].c);
160             }
161         }
162         // printf("MST ans=%I64d\n",ans);
163         dep[1]=1;
164         dfs(1,0,0);
165         BZ();
166         for (int i=1;i<=m;++i)
167         {
168             u=e[i].u;
169             v=e[i].v;
170             c=e[i].c;
171             Ans[e[i].idx]=ans+c-query(u,v);
172             // printf("query(%d,%d) = %d\n",u,v,query(u,v));
173         }
174         for (int i=1;i<=m;++i) printf("%I64d\n",Ans[i]);
175     }
176     return 0;
177 }

 

转载于:https://www.cnblogs.com/LeeSongt/p/9490169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值