zoukankan      html  css  js  c++  java
  • [Luogu P5680][GZOI2017]共享单车

    题目链接

    之前没看懂题意就把这题扔了,现在一看是读错题意了

    简化版题意

    给出一颗树(这个图的最短路径生成树),每个点初始颜色为(0)

    两种操作:

    1. 将部分点颜色取反

    2. 给出一些点,建出虚树(边权为两点树上距离),求最小割边代价使得虚树上没有颜色为(1)的点与根联通

    那这就很模板了:

    (f[x])表示(x)子树的答案,(c[x])表示(x)的颜色,则有转移方程:(当(f[K]=0)时输出(-1)

    [f[x]+=Val(x,y)quad (c[y]=1)\ f[x]+=min (Val(x,y),f[y])quad (c[y]=0) ]

    (注意以上方法没有考虑边权全为(0)但是答案不为(-1)的情况,不过好像没有这种数据,反正也不难特判就没管了)

    时间复杂度 (O((N+M)log N+Qnum(log num+log N)))

    (数据为什么这么小)

    代码:

    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    
    inline char Getchar()
    {
        static char In[1<<22],*p1=In,*p2=In;
        return p1==p2&&(p2=(p1=In)+fread(In,1,1<<22,stdin),p1==p2)?EOF:*p1++;
    }
    
    inline int Getint()
    {
        int x=0,c;
        while(!isdigit(c=Getchar()));
        for(;isdigit(c);c=Getchar())x=x*10+(c^48);
        return x;
    }
    
    const int N=50005,Inf=0x7f7f7f7f;
    int n,M,K,Q,Dis[N],Pre[N];
    int Dfn[N],Tim,Dep[N],f[N][16];
    int c[N],a[N],s[N],Top;
    std::vector<int> G[N],Gv[N],T[N],V[N];
    //Graph|Graph Value|Tree|Virtual Tree
    
    void Dijkstra()
    {
        struct Rec{int x,d;inline bool operator<(const Rec& o)const{return d>o.d;}};
        std::priority_queue<Rec> q;
        memset(Dis,0x7f,sizeof Dis);
        q.push((Rec){K,Dis[K]=0});
        while(!q.empty())
        {
            int x=q.top().x,d=q.top().d;
            if(q.pop(),d!=Dis[x])continue;
            for(int i=0,y,v;i<(int)G[x].size();++i)
                if(Dis[y=G[x][i]]>Dis[x]+(v=Gv[x][i])||(Dis[y]==Dis[x]+v&&x<Pre[y]))
                    q.push((Rec){y,Dis[y]=Dis[x]+v}),Pre[y]=x;
        }
        for(int i=1;i<=n;++i)if(i!=K)T[Pre[i]].push_back(i);
    }
    
    void DFS(int x,int Fa)
    {
        Dfn[x]=++Tim,Dep[x]=Dep[f[x][0]=Fa]+1;
        for(int i=1;i<=15;++i)f[x][i]=f[f[x][i-1]][i-1];
        for(auto y:T[x])if(y!=Fa)DFS(y,x);
    }
    
    int Lca(int x,int y)
    {
        if(Dep[x]<Dep[y])std::swap(x,y);
        for(int i=15;i>=0;--i)if(Dep[f[x][i]]>=Dep[y])x=f[x][i];
        if(x==y)return y;
        for(int i=15;i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        return f[y][0];
    }
    
    int DP(int x)
    {
        int Res=0;
        for(auto y:V[x])
        {
            int v=DP(y);
            if(c[y])Res+=Dis[y]-Dis[x];
            else Res+=std::min(v,Dis[y]-Dis[x]);
        }
        V[x].clear();
        return Res;
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        n=Getint(),M=Getint(),K=Getint(),Q=Getint();
        for(int i=1,x,y,z;i<=M;++i)
        {
            x=Getint(),y=Getint(),z=Getint();
            G[x].push_back(y),Gv[x].push_back(z);
            G[y].push_back(x),Gv[y].push_back(z);
        }
        Dijkstra(),DFS(K,0);
        for(int o,k;Q--;)
            if(o=Getint(),k=Getint(),!o)while(k--)c[Getint()]^=1;
            else
            {
                for(int i=1;i<=k;++i)a[i]=Getint();
                s[Top=1]=K,std::sort(a+1,a+k+1,[](int x,int y){return Dfn[x]<Dfn[y];});
                for(int i=1;i<=k;++i)
                {
                    int Ls=Lca(s[Top],a[i]);
                    while(Top>1&&Dfn[s[Top-1]]>=Dfn[Ls])V[s[Top-1]].push_back(s[Top]),--Top;
                    if(s[Top]!=Ls)V[Ls].push_back(s[Top]),s[Top]=Ls;
                    s[++Top]=a[i];
                }
                while(Top>1)V[s[Top-1]].push_back(s[Top]),--Top;
                int Ans=DP(K);
                printf("%d
    ",Ans?Ans:-1);
            }
        return 0;
    }
    
    
  • 相关阅读:
    Tjoi 2017 异或和
    Noi 十连测 建造记者站
    Noi 十连测 基因改造计划
    Noi 十连测 人生的经验
    NOI 十连测 Round 5 T2 运河计划
    NOI 十连测 Round 5 T1
    【ZJOI2018】迷宫
    BZOJ 十连测 day5 T3
    BZOJ 十连测 可持久化字符串
    BZOJ 十连测 二进制的世界
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/12173581.html
Copyright © 2011-2022 走看看