zoukankan      html  css  js  c++  java
  • 【洛谷6628】[省选联考 2020 B 卷] 丁香之路(欧拉路)

    点此看题面

    • 给定一张(n)个点的图,满足任意两点(i,j)之间存在一条边权为(|i-j|)的无向边。
    • 给定一个起点(s)以及(m)条必须经过的边,问对于每个终点(t=1sim n),从(s)(t)在经过所有必须经过的边的前提下的最短路。
    • (nle2500)

    欧拉路+并查集

    我们枚举一个(t),那么就是要在原图(强制经过的边)的基础上加上若干条边,满足存在一条从(s)(t)恰好经过所有边的路径。

    这等价于满足所有有边的点都连通,且存在从(s)(t)欧拉路(即只有(s,t)度数为奇数,其余点度数都是偶数)。

    我们可以在一开始就预先把强制给定的边全部表示到图上去,这一部分的复杂度是(O(m))的。

    接下来在已知(t)的时候,我们首先需要满足所有点度数都是偶数(对于起点和终点先给度数加上(1),那么也变成要满足是偶数了),这只要对所有需要修改度数的点两两配对即可(显然需要修改度数的总点数必然是偶数)。

    然后我们还需要满足连通,暴力的方式就是枚举所有连通块建图跑最小生成树。

    但由于此题边权的特殊性,实际上这里的最小生成树只需要考虑在相邻两点之间的连边,那么复杂度就正确了。

    代码:(O(n^2logn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 2500
    #define LL long long
    using namespace std;
    int n,m,s,a[N+5],d_[N+5],f_[N+5],d[N+5],f[N+5];I int fa(CI x) {return f[x]^x?f[x]=fa(f[x]):x;}//并查集
    int ee;struct edge {int x,y;I edge(CI a=0,CI b=0):x(a),y(b){}
    	I bool operator < (Con edge& o) Con {return y-x<o.y-o.x;}}e[N+5];//按边权排序
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    int main()
    {
    	RI i,j,k,x,y;LL t_=0;for(read(n,m,s),i=1;i<=n;++i) f[i]=i;
    	for(i=1;i<=m;++i) read(x,y),t_+=abs(x-y),++d[x],++d[y],f[fa(x)]=fa(y);//把强制选择的边表示到图上
    	RI p;LL t;for(i=1;i<=n;++i) d_[i]=d[i],f_[i]=f[i];for(i=1;i<=n;++i)
    	{
    		for(t=t_,j=1;j<=n;++j) d[j]=d_[j],f[j]=f_[j];++d[s],++d[i];//复制信息,预先给起点终点度数加1
    		for(p=0,j=1;j<=n;++j) if(d[j]&1) if(!p) p=j;else for(t+=j-(k=p),p=0;k^j;++k) f[fa(k)]=fa(j);//让度数都是偶数
    		for(p=ee=0,j=1;j<=n;++j) d[j]&&(p&&(e[++ee]=edge(p,j),0),p=j);//相邻两点建边
    		for(sort(e+1,e+ee+1),j=1;j<=ee;++j) (x=fa(e[j].x))^(y=fa(e[j].y))&&(t+=e[j].y-e[j].x<<1,f[x]=y);//最小生成树
    		printf("%d%c",t," 
    "[i==n]);
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    十六进制计算器
    USB 3.0规范中译本 第7章 链路层
    from表单POST提交nodejs
    07_通过谷歌封装的api操作数据库delete&insert
    06_直接执行sql操作数据库delete&update
    05_直接执行sql操作数据库
    04_数据库升级onUpgrade&ondowngrade
    03_通过OpenHelper获取SqliteDatabase对象
    02_SQliteOpenHelper介绍&oncreate方法介绍
    00_前情回顾&今日展望
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6628.html
Copyright © 2011-2022 走看看