zoukankan      html  css  js  c++  java
  • CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]

    题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边。


    这题还是要考察Kruskal的贪心过程。

    先跑一棵MST出来。然后考虑每条边。

    如果他是非树边,要让他Kruskal的时候被选入,必须要让他连的两个点$u,v$连通之前被选上,也就是说,必须得小于MST上$u,v$路径中的至少一条边,那么让他小于最大的那条(减一)即可。

    如果他是树边,那么考虑如果删去他,他连接的两点如果要连通,可否用其他边替换。发现一定可以用经过这条边的非树边替换他,且会使用最小的一条非树边作为新的MST的边。所以只要找到路径覆盖这条边的所有非树边的最小的减一即可。

    综上,我们需要做树上链查询$max$,链取$min$的操作,并且这两个操作相互独立。我一开始写了一个倍增,结果欠思考,在取$min$操作上卡住了。。所以我重新写了一个树剖分别维护两个信息。复杂度$O(nlog^2 n)$,吊打单$log$。

      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 struct thxorz{int to,nxt,w;}G[N<<1];
     24 int Head[N],tot=1;
     25 int ans[N],used[N];
     26 int n,m;
     27 inline void Addedge(int x,int y,int z){
     28     G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;
     29     G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z;
     30 }
     31 int fa[N],topfa[N],dep[N],son[N],sum[N],pos[N],A[N],cnt;
     32 #define y G[j].to
     33 void dfs1(int x,int f){
     34     fa[x]=f;dep[x]=dep[G[f^1].to]+1;sum[x]=1;int tmp=-1;
     35     for(register int j=Head[x];j;j=G[j].nxt)if((j^1)^f)dfs1(y,j),sum[x]+=sum[y],MAX(tmp,sum[y])&&(son[x]=y);
     36 }
     37 void dfs2(int x,int topf){
     38     topfa[x]=topf;pos[x]=cnt,A[cnt++]=G[fa[x]].w;if(!son[x])return;dfs2(son[x],topf);
     39     for(register int j=Head[x];j;j=G[j].nxt)if((j^1)^fa[x]&&y^son[x])dfs2(y,y);
     40 }
     41 #undef y
     42 struct segment_tree{
     43     int maxv[N<<2],cov[N<<2],tag[N<<2];
     44     #define lc i<<1
     45     #define rc i<<1|1
     46     segment_tree(){memset(cov,0x3f,sizeof cov),memset(tag,0x3f,sizeof tag);}
     47     inline void pushdown(int i){
     48         if(tag[i]<INF){MIN(tag[lc],tag[i]),MIN(tag[rc],tag[i]);MIN(cov[lc],tag[i]),MIN(cov[rc],tag[i]);tag[i]=INF;}
     49     }
     50     void Build(int i,int L,int R){
     51         if(L==R){maxv[i]=A[L];return;}
     52         Build(lc,L,L+R>>1),Build(rc,(L+R>>1)+1,R);maxv[i]=_max(maxv[lc],maxv[rc]);
     53     }
     54     int UPD(int i,int L,int R,int ql,int qr,int val){
     55         if(ql<=L&&qr>=R){MIN(cov[i],val);MIN(tag[i],val);return maxv[i];}
     56         int mid=L+R>>1,ret=0;pushdown(i);
     57         if(ql<=mid)MAX(ret,UPD(lc,L,mid,ql,qr,val));
     58         if(qr>mid)MAX(ret,UPD(rc,mid+1,R,ql,qr,val));
     59         cov[i]=_min(cov[lc],cov[rc]);return ret;
     60     }
     61     int Query_cover(int i,int L,int R,int x){
     62         if(L==R)return cov[i];
     63         int mid=L+R>>1;pushdown(i);
     64         if(x<=mid)return Query_cover(lc,L,mid,x);
     65         return Query_cover(rc,mid+1,R,x);
     66     }
     67 }T;
     68 
     69 struct wphorz{
     70     int u,v,w,id;
     71     inline bool operator <(const wphorz&A)const{return w<A.w;}
     72 }e[N];
     73 struct dsu{
     74     int anc[N];
     75     inline void Clear(){for(register int i=1;i<=n;++i)anc[i]=i;}
     76     inline int Find(int x){return anc[x]==x?x:anc[x]=Find(anc[x]);}
     77 }S;
     78 inline void Kruskal(){
     79     sort(e+1,e+m+1);S.Clear();//for(register int i=1;i<=m;++i)printf("%d %d %d
    ",e[i].u,e[i].v,e[i].w);    
     80     for(register int i=1;i<=m;++i)if(S.Find(e[i].u)^S.Find(e[i].v))
     81         S.anc[S.anc[e[i].u]]=S.anc[e[i].v],Addedge(e[i].u,e[i].v,e[i].w),used[i]=1;
     82 }
     83 inline int qry_and_upd(int x,int y,int val){
     84     int ret=0;
     85     while(topfa[x]^topfa[y]){
     86         if(dep[topfa[x]]<dep[topfa[y]])_swap(x,y);
     87         MAX(ret,T.UPD(1,1,n-1,pos[topfa[x]],pos[x],val));
     88         x=G[fa[topfa[x]]^1].to;
     89     }
     90     if(dep[x]>dep[y])_swap(x,y);
     91     return _max(ret,x==y?0:T.UPD(1,1,n-1,pos[x]+1,pos[y],val));
     92 }
     93 inline void process(){
     94     for(register int i=1;i<=m;++i)if(!used[i])ans[e[i].id]=qry_and_upd(e[i].u,e[i].v,e[i].w)-1;
     95     for(register int i=1;i<=m;++i)if(used[i]){//printf("%d %d
    ",e[i].id,e[i].w);
     96         if(dep[e[i].u]<dep[e[i].v])_swap(e[i].u,e[i].v);
     97         ans[e[i].id]=T.Query_cover(1,1,n-1,pos[e[i].u]);
     98         ans[e[i].id]<INF?ans[e[i].id]--:ans[e[i].id]=-1;
     99     }//puts("");
    100     for(register int i=1;i<=m;++i)printf("%d ",ans[i]);puts("");
    101 }
    102 
    103 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    104     read(n),read(m);
    105     for(register int i=1;i<=m;++i)read(e[i].u),read(e[i].v),read(e[i].w),e[i].id=i;
    106     Kruskal();dfs1(1,0),dfs2(1,1);
    107     T.Build(1,1,n-1);process();
    108     return 0;
    109 }
    View Code

    事实上,倍增那种方法也不是不可以,只不过取$min$操作只要离线在节点上打标记,$x,y$处标记插入值,$lca$处标记删除之,然后用set维护最小值,dfs自下而上启发式合并更新即可。复杂度$O(nlog^2 n)$。还可以把set改成可并堆,然后删除的话用懒惰删除法(见lyd书),然后做到一个$log$。

    另外一种方法,直接LCT。

    总结:掌握好Kruskal本质是关键。

  • 相关阅读:
    输入三个整数x,y,z,请把这三个数由小到大输出
    随机三位数
    球反弹高度
    成绩分类
    java判断开头结尾
    二分法查找
    Leetcode 6. ZigZag Conversion(找规律,水题)
    Leetcode 5. Longest Palindromic Substring(最长回文子串, Manacher算法)
    Leetcode 4. Median of Two Sorted Arrays(中位数+二分答案+递归)
    Leetcode 3. Longest Substring Without Repeating Characters(string 用法 水题)
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11691260.html
Copyright © 2011-2022 走看看