zoukankan      html  css  js  c++  java
  • Atcoder CODE FESTIVAL 2016 Final G

    题意:$n$个点,$q$次建边,每次建边选定$x,y$,权值$c$,然后接着$(y,x+1,c+1),(x+1,y+1,c+2),(y+1,x+2,c+3),(x+2,y+2,c+4)dots$(画图理解),然后求最小生成树。


    一开始想的是堆维护最小。。发现不行`````

    这题是等效转化。回顾kruskal的过程,权值小的边被考虑过后对应的两个点一定是联通的。那么其实再考虑权值大的边的话,是可以改造的。当$(x,y)$被考虑过后,权值大的$(y,x+1)$其实就可以改成是$(x,x+1)$,都是等价的。$(x+1,y+1)$也可以改成是$(y,y+1)$。以此类推,就可以把除了起始状态的边以外的乱七八糟的连边全都搞到一个大环上,然后环上同一个相邻连边里取最小值,做Kruskal,一定是对的,这样一来因为边被搞少了很多,只有$O(n+q)$条边,就可以做kruskal了。

    还有一个问题,每个点为起始点,往后相邻点连边,如果每次操作都绕环一圈更新每条边的min,显然T飞。又因为这是环状结构,所以直接找出最小的出发连边,这条边一定不会被后面的给更新掉,从她开始沿着环开始顺时针更新,一路上一遍做出发边前缀最小值一遍连边就可以了,这个要以$x$端点和$y$端点各做一次。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define dbg(x) cerr << #x << " = " << x <<endl
     8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef double db;
    12 typedef pair<int,int> pii;
    13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    18 template<typename T>inline T read(T&x){
    19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    21 }
    22 const int N=2e5+7,INF=0x3f3f3f3f;
    23 int n,q,tot;
    24 struct thxorz{
    25     int u,v,w;
    26     thxorz(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
    27     inline bool operator <(const thxorz&A)const{return w<A.w;}
    28 }e[N<<1];
    29 inline int adj(int x){return x==n?0:(~x?x:n-1);}
    30 int minv1[N],minv2[N],edge[N];
    31 int s,tmp,res;
    32 ll ans;
    33 int anc[N];
    34 inline int get_anc(int x){return anc[x]==x?x:anc[x]=get_anc(anc[x]);}
    35 inline void kruskal(){
    36     sort(e+1,e+tot+1);for(register int i=0;i<n;++i)anc[i]=i;
    37     for(register int i=1;i<=tot;++i)if(get_anc(e[i].u)^get_anc(e[i].v))anc[get_anc(e[i].u)]=get_anc(e[i].v),ans+=e[i].w;
    38 }
    39 
    40 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    41     read(n),read(q);
    42     memset(minv1,0x3f,sizeof minv1),memset(minv2,0x3f,sizeof minv2),memset(edge,0x3f,sizeof edge);
    43     for(register int i=1,x,y,c;i<=q;++i)read(x),read(y),read(c),MIN(minv1[x],c),MIN(minv2[y],c),e[++tot]=thxorz(x,y,c);
    44     tmp=INF;for(register int i=0;i<n;++i)if(MIN(tmp,minv1[i]))s=i;tmp=INF;
    45     for(register int i=s,cnt=1;cnt<=n;i=adj(i+1),++cnt){if((tmp+=2)>minv1[i]+1)tmp=minv1[i]+1;MIN(edge[i],tmp);}
    46     tmp=INF;for(register int i=0;i<n;++i)if(MIN(tmp,minv2[i]))s=i;tmp=INF;
    47     for(register int i=s,cnt=1;cnt<=n;i=adj(i+1),++cnt){if((tmp+=2)>minv2[i]+2)tmp=minv2[i]+2;MIN(edge[i],tmp);}
    48     for(register int i=0;i<n;++i)e[++tot]=thxorz(i,adj(i+1),edge[i]);
    49     kruskal();
    50     return printf("%lld
    ",ans),0;
    51 }
    View Code

    总结:等效转化的应用。当边如果某些方面连边有规律的时候,利用kruskal过程,把权值相对某些边大的,转化为方便处理/减少连边的方案。

  • 相关阅读:
    浅谈Static关键字
    iOS安装CocoaPods详细过程
    解决最新版 mac os sierra usb网卡不能使用的问题
    pyCharm最新2017激活码
    开发中所使用的渠道(统计分析、分享、第三方登录、短信等)
    oc中文首字母排序
    UIFont 设置字体
    iOS运用runtime全局修改UILabel的默认字体
    OC录制小视频
    OC
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11672841.html
Copyright © 2011-2022 走看看