zoukankan      html  css  js  c++  java
  • 入门OJ:八中生成树2

    题目描述

    八中里面有N个建设物,M条边。对于这种要建最小生成树的问题,你应该很熟练了。现在老大决定降低某条边的费用,然后这条边必须要被选中,因为这条路他每天都要走,自然......问选了这条边后是否可以得到一个比从前总开支相等或更小的方案。

    输入格式

    第一行三个整数N,M,Q(1<=N<=1000,N-1<=M<=100000接下来M行,每行三个整数(X,Y,Z)描述一条可以建造的路。 0<=Z<=10000 最后Q行,每行两个整数i,x(1<=i<=M,0<=x)描述一个修改计划,即要你判断如果 将第i条公路的修建费用降低为x元后,是否可以得到一个比从前总开支相等或更小的方案

    输出格式

    按顺序输出Q行,每行输出"Yes"或"No",Yes表示可以建造,No表示不可能


    先考虑暴力。

    我们可以每次询问之后都修改一次边权,然后在原图求一次最小生成树,看是否更优即可。时间复杂度为O(Q * MlogM)

    其实在原图再求一次mst时基本上所有边都是不需要变动的。可以利用这一点考虑优化

    如果询问给出的边是树上边,那么只需比较和原来的树边大小即可。

    如果不是树上边,那么如果原树不变,只加上询问的边,就会形成一个环。设询问给出的边为E(u,v),那么这个环就可以表示为:u->LCA(u,v)->v->u。所以生成树上唯一需要改变的就是这个环上的部分。只需要把环断掉一条边即可。为了使断掉之后的生成树尽可能小,我们肯定会断掉环上最长的边(除了询问给的边)。所以问题就变成了:求路径u->LCA(u,v)->v上最长边。

    可以用倍增做,时间复杂度为O((N+M)logN),总复杂度就是:O((N+Q)logN+MlogM)。也可以树剖直接做,复杂度为O(QlogNlogN+MlogM)。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 1001
    #define maxm 100001
    using namespace std;
     
    struct brim{
        int u,v,w;
        bool operator<(const brim &b)const{ return w<b.w; }
    }b[maxm],tmp[maxm];
     
    struct edge{
        int to,dis,next;
        edge(){}
        edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
    }e[maxn<<1];
    int head[maxn],k;
     
    struct node{
        int l,r,c;
    }t[maxn<<2];
     
    int anc[maxn];
    int size[maxn],fa[maxn],son[maxn],dep[maxn];
    int top[maxn],dfn[maxn],id[maxn],tot;
    bool vis[maxn];
    int n,m,q,val[maxn];
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    inline void add(const int &u,const int &v,const int &w){
        e[k]=edge(v,w,head[u]);
        head[u]=k++;
    }
     
    int get(int x){ return anc[x]==x?x:anc[x]=get(anc[x]); }
    inline int kruskal(){
        for(register int i=1;i<=n;i++) anc[i]=i;
        for(register int i=1;i<=m;i++) tmp[i]=b[i];
        sort(tmp+1,tmp+1+m);
        for(register int i=1;i<=m;i++){
            int u=tmp[i].u,v=tmp[i].v,w=tmp[i].w;
            if(get(u)==get(v)) continue;
            anc[get(u)]=get(v),add(u,v,w),add(v,u,w);
        }
    }
     
    void dfs_getson(int u){
        size[u]=1;
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v==fa[u]) continue;
            dep[v]=dep[u]+1,fa[v]=u;
            dfs_getson(v);
            size[u]+=size[v];
            if(size[v]>size[son[u]]) son[u]=v;
        }
    }
    void dfs_rewrite(int u,int tp){
        top[u]=tp,dfn[u]=++tot,id[tot]=u;
        if(son[u]) dfs_rewrite(son[u],tp);
        for(register int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(v!=son[u]&&v!=fa[u]) dfs_rewrite(v,v);
        }
    }
    inline void endow(){
        for(register int i=0;i<k;i+=2){
            int u=e[i].to,v=e[i^1].to;
            if(dep[u]>dep[v]) swap(u,v);
            val[v]=e[i].dis;
        }
    }
     
    void build(int d,int l,int r){
        t[d].l=l,t[d].r=r;
        if(l==r){ t[d].c=val[id[l]]; return; }
        int mid=l+r>>1;
        build(d<<1,l,mid),build(d<<1|1,mid+1,r);
        t[d].c=max(t[d<<1].c,t[d<<1|1].c);
    }
    int getmax(int d,const int &l,const int &r){
        if(l<=t[d].l&&t[d].r<=r) return t[d].c;
        int mid=t[d].l+t[d].r>>1,ans=0;
        if(l<=mid) ans=max(ans,getmax(d<<1,l,r));
        if(r>mid) ans=max(ans,getmax(d<<1|1,l,r));
        return ans;
    }
     
    int main(){
        memset(head,-1,sizeof head);
        n=read(),m=read(),q=read();
        for(register int i=1;i<=m;i++) b[i].u=read(),b[i].v=read(),b[i].w=read();
        kruskal();
     
        dfs_getson(1);
        dfs_rewrite(1,1);
        endow();
        build(1,1,tot);
     
        for(register int i=1;i<=q;i++){
            int id=read(),w=read(),mmax=0,u=b[id].u,v=b[id].v;
            while(top[u]!=top[v]){
                if(dep[top[u]]>dep[top[v]]) swap(u,v);
                mmax=max(mmax,getmax(1,dfn[top[v]],dfn[v]));
                v=fa[top[v]];
            }
            if(dep[u]>dep[v]) swap(u,v);
            if(u!=v) mmax=max(mmax,getmax(1,dfn[u]+1,dfn[v]));
            printf("%s
    ",mmax-w>=0?"Yes":"No");
        }
        return 0;
    }
    
  • 相关阅读:
    serial number
    python getopt
    python readline,seek
    linux scp
    jenkinsapi
    windows kill process
    python time
    python configparse
    解决某些.net不方便解决的问题,解决方法就是 DHTML
    (转)windows XP 系统服务“关闭”详细列表,释放N多内存,128也够用了!
  • 原文地址:https://www.cnblogs.com/akura/p/10885980.html
Copyright © 2011-2022 走看看