zoukankan      html  css  js  c++  java
  • Codeforces 1220E. Tourism

    传送门

    这是一道英语题,首先要读懂题目:

    $ ext{Alex believes that his trip will be interesting only if he will not use any road twice in a row.}$

    这句话意思是不会连续走一条路,但是同一条路是可以走多次的

    所以对于一个边双联通分量,是可以全部走一遍并可以从联通分量里的任意一个点离开的

    所以就可以直接缩点,然后就变成树上问题

    发现对于树上的点,如果它的大小为 $1$ 并且它的儿子都没法返回 ,那么到达它以后就没法返回,反之一定可以返回(自己内部绕一圈或者走到儿子再回来即可)

    考虑树上搞搞 $dp$,设 $f[x]$ 表示走完 $x$ 的子树以后并能返回 $x$ 的父亲时得到的最大价值,$g[x]$ 表示走完 $x$ 的子树不返回的最大价值

    那么对于一个可以返回父亲的的子节点 $v$ ,有转移:$f[x]+=f[v]$

    对于 $g[x]$ ,比较复杂,首先 $g[x]$ 可以是 $x$ 走完所有可以返回的儿子,最后再走到一个不能返回的儿子:$g[x]=f[x]+g[v]$

    也可以是走到某个虽然可以返回,但是没必要返回的儿子里面不返回(因为儿子再往下走到不能返回的节点最终价值可能更大):$g[x]=g[x]-f[v]+g[v]$,这里减去 $f[v]$ 是因为之前加上了

    然后最后答案就是 $g[root]$

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=4e5+7;
    int n,m,a[N];
    int fir[N],from[N<<1],to[N<<1],cntt;
    inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
    int dfn[N],low[N],bel[N],st[N],sz[N],Top,cnt,tot;
    void Tarjan(int x,int fa)
    {
        dfn[x]=low[x]=++cnt; st[++Top]=x;
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(v==fa) continue;
            if(!dfn[v]) Tarjan(v,x),low[x]=min(low[x],low[v]);
            else if(!bel[v]) low[x]=min(low[x],dfn[v]);
        }
        if(low[x]!=dfn[x]) return;
        tot++; while(st[Top]!=x) bel[st[Top--]]=tot;
        bel[st[Top--]]=tot;
    }
    struct edge {
        int u,v;
        edge (int _u=0,int _v=0) { u=_u,v=_v; }
        inline bool operator < (const edge &tmp) const {
            return u!=tmp.u ? u<tmp.u : v<tmp.v;
        }
        inline bool operator == (const edge &tmp) const {
            return u==tmp.u&&v==tmp.v;
        }
    };
    vector <edge> tmp;
    vector <int> V[N];
    ll val[N];
    void build()
    {
        for(int i=1;i<=n;i++) val[bel[i]]+=a[i],sz[bel[i]]++;
        for(int i=1;i<=n;i++)
            for(int j=fir[i];j;j=from[j])
            {
                int &v=to[j]; if(bel[i]==bel[v]) continue;
                tmp.push_back(edge(bel[i],bel[v]));
            }
        sort(tmp.begin(),tmp.end());
        tmp.resize( unique(tmp.begin(), tmp.end()) - tmp.begin() );
        for(auto E: tmp) V[E.u].push_back(E.v);
    }
    ll f[N],g[N];
    bool ret[N];
    void dfs(int x,int fa)
    {
        f[x]=val[x]; if(sz[x]>1) ret[x]=1;
        ll mx=0;
        for(auto v:V[x])
        {
            if(v==fa) continue;
            dfs(v,x);
            if(ret[v]) f[x]+=f[v],ret[x]=1;
            else mx=max(mx,g[v]);
        }
        g[x]=f[x]+mx;
        for(auto v:V[x])
            if(v!=fa&&ret[v])
                g[x]=max(g[x], f[x]-f[v]+g[v] );
    }
    int main()
    {
        n=read(),m=read(); int x,y;
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read();
            add(x,y); add(y,x);
        }
        int s=read();
        for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i,0);
        build();
        dfs(bel[s],0);
        printf("%lld
    ",g[bel[s]]);
        return 0;
    }
  • 相关阅读:
    鱼群生长曲线分析
    记住这一刻,学会感恩
    编译boost命令
    ASP之SOAP的发送、接收与处理类[转载]
    在WinForm中使用WebServices来实现软件自动升级(AutoUpdate)(C#)[转载]
    .Net下采用GET/POST/SOAP方式动态调用WebService的简易灵活方法(C#) [轉]Redfox
    使用 HttpWebRequest 类调用 WEB 服务的示例(C#)【转载】
    Log4Net使用指南
    C# post xml using HttpWebRequest/Response
    XmlHttp对象简介[转载]
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11556396.html
Copyright © 2011-2022 走看看