首页 > 其他分享 >P4412 题解

P4412 题解

时间:2023-08-14 21:45:32浏览次数:40  
标签:int 题解 边权 add edge eid P4412 id

P4412 题解

传送门 更好的阅读体验


简化题意:一张无向图,给定一棵生成树,求最小的修改边权的代价使得这棵生成树是最小生成树,代价定义为修改前后一条边的边权变化量的绝对值。

思路


首先,发现让这棵树成为最小生成树不好直接处理,但是判定是否为最小生成树却相对更容易。判定的思路也很简单,对于每一条非树边 $(x,y)$,树上 $x$ 到 $y$ 的路径上的任意一条边边权都不能超过这条非树边的边权。
显然,树上的边边权一定不会减小,非树边边权一定不会变大。于是对于一条非树边 $y$ 和在树上的一条边 $x$,有 $w_x+|\Delta x|\geqslant w_y-|\Delta y|$,即 $|\Delta x|+|\Delta y|\geqslant w_y-w_x$。那我们把每一条边当做一个点,点权就是原来的边权,发现原问题就是**最小顶标号**问题,直接求二分图最大权完美匹配可以了。
由于不会写KM算法,就写了费用流。
贴一下代码  
  1 const int N=55,M=1551;
  2 int n,m;
  3 int e[N][N];
  4 struct node{
  5     int x,y,z;
  6 }edge[M];
  7 bool mark[M];
  8 int cnt,ver[M],nxt[M],h[N],w[N],fa[N],eid[N],dep[N],id[N];
  9 namespace Graph{
 10     int cnt=1,ver[M<<6],nxt[M<<6],w[M<<6],c[M<<6],h[M<<1],s,t;
 11     inline void add_edge(int x,int y,int z,int cost){
 12         // cout<<x<<" "<<y<<" "<<cost<<endl;
 13         cnt++;ver[cnt]=y;nxt[cnt]=h[x];h[x]=cnt;w[cnt]=z;c[cnt]=cost;
 14         cnt++;ver[cnt]=x;nxt[cnt]=h[y];h[y]=cnt;w[cnt]=0;c[cnt]=-cost;
 15     }
 16     int flow[M<<1],dis[M<<1],lst[M<<1],pre[M<<1];
 17     bool vis[M<<1];
 18     inline bool bfsmax(){
 19         queue<int>q;
 20         memset(dis,0xc0,sizeof(dis));
 21         memset(flow,0x3f,sizeof(flow));
 22         memset(vis,0,sizeof(vis));
 23         q.push(s);vis[s]=1,dis[s]=0,pre[t]=-1;
 24         while(q.size()){
 25             int x=q.front();
 26             q.pop();
 27             vis[x]=0;
 28             for(int i=h[x];i;i=nxt[i]){
 29                 int y=ver[i];
 30                 if(w[i]>0&&dis[y]<dis[x]+c[i]){
 31                     dis[y]=dis[x]+c[i];
 32                     pre[y]=x;lst[y]=i;
 33                     flow[y]=min(w[i],flow[x]);
 34                     if(!vis[y]){
 35                         vis[y]=1;
 36                         q.push(y);
 37                     }
 38                 }
 39             }
 40         }
 41         return pre[t]!=-1;
 42     }
 43     inline int getmax(){
 44         int maxc=0;
 45         while(bfsmax()){
 46             if(dis[t]<0)break;
 47             maxc+=flow[t]*dis[t];
 48             int cur=t;
 49             while(cur!=s){
 50                 w[lst[cur]]-=flow[t];
 51                 w[lst[cur]^1]+=flow[t];
 52                 cur=pre[cur];
 53             }
 54         }
 55         return maxc;
 56     }
 57     inline int solve(){
 58         s=0,t=m+1;
 59         for(int i=1;i<n;i++)add_edge(s,i,1,0);
 60         for(int i=n;i<=m;i++)add_edge(i,t,1,0);
 61         return getmax();
 62     }
 63 }
 64 inline void add_edge(int x,int y,int z){cnt++;ver[cnt]=y;nxt[cnt]=h[x];h[x]=cnt;w[cnt]=z;}
 65 inline void dfs(int x){
 66     dep[x]=dep[fa[x]]+1;
 67     for(int i=h[x];i;i=nxt[i]){
 68         int y=ver[i];
 69         if(y!=fa[x]){
 70             fa[y]=x;
 71             eid[y]=w[i];
 72             dfs(y);
 73         }
 74     }
 75 }
 76 inline void modify(int x,int y,int z){
 77     if(dep[x]<dep[y])swap(x,y);
 78     while(dep[x]>dep[y]){
 79         Graph::add_edge(id[eid[x]],id[z],1,edge[eid[x]].z-edge[z].z);
 80         x=fa[x];
 81     }
 82     while(x^y){
 83         Graph::add_edge(id[eid[x]],id[z],1,edge[eid[x]].z-edge[z].z);
 84         Graph::add_edge(id[eid[y]],id[z],1,edge[eid[y]].z-edge[z].z);
 85         x=fa[x],y=fa[y];
 86     }
 87 }
 88 int main(){
 89     ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
 90     cin>>n>>m;
 91     for(int i=1;i<=m;i++){
 92         int x,y,z;
 93         cin>>x>>y>>z;
 94         e[x][y]=e[y][x]=i;
 95         edge[i]=(node){x,y,z};
 96     }
 97     for(int i=1;i<n;i++){
 98         int x,y;
 99         cin>>x>>y;
100         mark[e[x][y]]=1;
101         add_edge(x,y,e[x][y]);add_edge(y,x,e[x][y]);
102     }
103     for(int i=1,t1=0,t2=n-1;i<=m;i++){
104         if(mark[i])id[i]=++t1;
105         else id[i]=++t2;
106     }
107     dfs(1);
108     for(int i=1;i<=m;i++){
109         if(!mark[i]){
110             int x=edge[i].x,y=edge[i].y;
111             modify(x,y,i);
112         }
113     }
114     cout<<Graph::solve()<<endl;
115     return 0;
116 }

 

标签:int,题解,边权,add,edge,eid,P4412,id
From: https://www.cnblogs.com/Xttttr/p/17629845.html

相关文章

  • CF1845D Rating System 题解
    题面给定一个长度为\(n\)数列\(a\),保证每项都不为\(0\)。初始时\(x=0\),然后对于\(1\lei\len\),按顺序进行如下操作:如果\(x\gek\),则\(x\rightarrow\max(k,x+a_i)\),否则\(x\rightarrowx+a_i\)。你需要求出\(k\),使得\(x\)的值尽量大。题解如果我们不考虑\(k......
  • Ynoi2001 冷たい部屋、一人 题解
    \(\text{link}\),这题太毒瘤啦!难写难调还略微卡常。谁爱卡常谁卡吧。反正我先贺为敬了。——引用自洛谷别人的提交记录本人写了两天(两个\(case\)各一天),调崩溃了才调出来,太毒瘤了!看到颜色相同发现不弱于\(O(n\sqrtn)\),一眼根号分治,设阈值为\(B\)。case1对于颜色出现次......
  • [ARC126C] Maximize GCD 题解
    题意给定一个序列\(A\),每次操作可以使\(A_i+1\)(\(i\in\left[1,n\right]\),\(K\)次操作的\(i\)可以不同),最多可以做\(K\)次。问\(\gcd{A_1,A_2,...,A_n}\)的最大值。题解首先,如果\(K\)可以把当前序列中所有的数都加到\(A_{\max}\),那就全部加到\(A_{\max}\),在......
  • [ABC215D] Coprime 2 题解
    题意给定数列\(A_N\)和一个正整数\(M\),求出所有的\(1\lek\leM\)满足\(\foralli\in\left[1,N\right],\gcd(k,A_i)=1\)。题解本题存在线性复杂度算法。记\(\operatorname{lpf}(n)=[1<n]\min\{p:p\midn\}+[1=n]\),即\(n\)的最小质因数。特别地,\(n......
  • [ARC126D] Pure Straight 题解
    题意给定一个有\(N\)个正整数的序列\(A=(A_1,A_2,\cdots,A_N)\),且\(A_i\in\left[1,K\right]\)。你可以对这个序列做如下操作若干次。交换两个相邻的元素,也就是选出\(i\)和\(j\)满足\(\lverti-j\rvert=1\)并交换\(A_i\)和\(A_j\)。找到最小的操作数使\(......
  • CF793F Julia the snail 题解
    题意有一个长为\(n\)的杆,上面有\(m\)条绳子,每条绳子可以让蜗牛从\(l_i\)爬到\(r_i\)(中途不能离开),保证\(r_i\)各不相同。蜗牛也可以自然下落。现在有\(q\)次询问,询问\(x\)出发,途中高度不能低于\(x\)或高于\(y\),问最高能爬到的位置。\(n,m,q\leq10^5\)。题解......
  • 【免费分享 图书】《阿里云天池大赛赛题解析——机器学习篇》-PDF电子书-百度云
    找这本书的资源简直要把我找吐了,各种网站压缩包一下下来就开始各种套路(比如要你充钱)为了防止还有我这样的受害者,这就把找到的PDF给大家分享一下。链接在文章最后如果这篇文章能够帮到您,麻烦帮我点个赞,并关注一下我,我有更多动力,持续分享更多有用图书给您!非常感谢,不胜感激!(点关......
  • 「题解注释」P3345 [ZJOI2015] 幻想乡战略游戏
    题解P3345【[ZJOI2015]幻想乡战略游戏】-Baka'sBlog-洛谷博客(luogu.org)耗时:半个下午代码注释:#include<bits/stdc++.h>typedeflonglongLL;inlineintrd(){ inta=1,b=0;charc=getchar(); while(!isdigit(c))a=c=='-'?0:1,c=getcha......
  • CF1859C 题解
    思路我们实际上发现它计算的就是\(p_i\cdoti\)的和再减去一个\(p_i\cdoti\)中的最大值。那我们可以枚举这个最大值\(p_x\cdotx\),这个值就是最后和中需要删除的数值。这里我们可以使用贪心。我们可以从\(n\sim1\)枚举除\(p_i\)的每个数字需要配的数字。当然,......
  • CF1859B 题解
    题意给定\(n\)个长度为\(m\)的数组,每个数组可以向别的数组转移最多一个数字,任意一个数组都可以接受无穷多的数字,最大化每个数组的最小值之和。做法考虑贪心。我们记第\(i\)个数组的第\(j\)个数字为\(a_{i,j}\)。我们先对每一个数组按照升序进行排序,那我们最不愿意......