zoukankan      html  css  js  c++  java
  • BZOJ4016: [FJOI2014]最短路径树问题

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=4016

    最短路+点分治。。

    首先要把最短路径树做出来吧。。于是先跑一遍spfa,然后bfs一遍就可以建出树了。。

    然后点分。。对于以重心为根的那棵子树,一棵一棵子树拿出来,维护处dep和dis(到根的距离),然后更新答案。

    设g[i][0]为深度为i的路径的最大距离,g[i][1]为当前这个最大距离下的路径个数。

    这样维护还算是比较简单的吧。。。

    感人肺腑的是没怎么调,过样例就A了。。更感人肺腑的是速度垫底了TAT。。

    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define maxn 60059
    #define inf int(1e9)
    using namespace std;
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    struct data{int obj,pre,c;
    }e[maxn*4],ed[maxn*4];
    int head[maxn],head2[maxn],s[maxn],dis[maxn],vis[maxn],q[maxn],fa[maxn],dep[maxn],g[maxn][2],sz[maxn];
    int n,m,sum,K,ans,ans2,mx,rt,tot,tot2;
    void insert(int x,int y,int z){
        e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot; e[tot].c=z;
    }
    void insert2(int x,int y,int z){
        ed[++tot2].obj=y; ed[tot2].pre=head2[x]; head2[x]=tot2; ed[tot2].c=z;
    }
    void spfa(){
        queue<int> q; q.push(1); clr(vis,0); vis[1]=1; 
        rep(i,1,n) dis[i]=inf; dis[1]=0;
        while (!q.empty()){
            int u=q.front(); q.pop(); vis[u]=0;
            for (int j=head2[u];j;j=ed[j].pre){
                int v=ed[j].obj;
                if (dis[v]>dis[u]+ed[j].c){
                    dis[v]=dis[u]+ed[j].c;
                    if (!vis[v]) vis[v]=1,q.push(v);
                }
            }
            vis[u]=0;
        }
    }
    void bfs(){
        priority_queue<int> q; q.push(-1); clr(vis,0); vis[1]=1;
        while (!q.empty()){
            int u=-q.top(); q.pop(); 
            for (int j=head2[u];j;j=ed[j].pre){
                int v=ed[j].obj;
                if (vis[v]||dis[v]!=dis[u]+ed[j].c) continue;
                insert(u,v,ed[j].c); insert(v,u,ed[j].c); vis[v]=1; q.push(-v); 
            }
        } 
    }
    int dfs(int u,int f){
        s[u]=1;
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (v!=f) s[u]+=dfs(v,u);
        }
        return s[u];
    }
    void getroot(int u,int f){
        sz[u]=0;
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (vis[v]||v==f) continue;
            getroot(v,u);
            sz[u]=max(sz[u],s[v]);
        }
        sz[u]=max(sz[u],sum-s[u]);
        if (sz[u]<mx) mx=sz[u],rt=u;
    }
    void go(int u){
        for (int j=head[u];j;j=e[j].pre){
            int v=e[j].obj;
            if (vis[v]) continue;
            dep[v]=1; dis[v]=e[j].c; fa[v]=u;
            int l=0,r=1; q[1]=v;
            while (l<r){
                int now=q[++l];
                for (int k=head[now];k;k=e[k].pre){
                    int v=e[k].obj;
                    if (v==fa[now]||vis[v]) continue;
                    fa[v]=now; dis[v]=dis[now]+e[k].c; dep[v]=dep[now]+1; q[++r]=v;
                }
            }
            rep(i,1,r){
                int x=dep[q[i]]; fa[q[i]]=0;
                if (x>=K) break;
                if (dis[q[i]]+g[K-x-1][0]>ans) ans=dis[q[i]]+g[K-x-1][0],ans2=g[K-x-1][1];
                else if (dis[q[i]]+g[K-x-1][0]==ans) ans2+=g[K-x-1][1];
            }
            rep(i,1,r){
                int x=dep[q[i]];
                if (x>=K) break;
                if (x==K-1){
                    if (dis[q[i]]>ans) ans=dis[q[i]],ans2=1;
                    else if (dis[q[i]]==ans) ans2++;
                    continue;
                } 
                if (dis[q[i]]>g[x][0]) g[x][0]=dis[q[i]],g[x][1]=1;
                else if (dis[q[i]]==g[x][0]) g[x][1]++;
            }
        } 
    }
    void solve(int u){
        rt=0; mx=inf;
        getroot(u,0);
        rep(i,1,K) g[i][0]=-inf,g[i][1]=0;
        go(rt);
        vis[rt]=1;
        for (int j=head[rt];j;j=e[j].pre){
            int v=e[j].obj;
            if (!vis[v]) sum=s[v],solve(v);
        }
    }
    int main(){
        n=read(); m=read(); K=read();
        rep(i,1,m) {
            int x=read(),y=read(),z=read();
            insert2(x,y,z); insert2(y,x,z);
        }
        spfa();
        bfs(); dfs(1,0);
        clr(vis,0);
        sum=n; solve(1);
        printf("%d %d
    ",ans,ans2);
        return 0;
    }
  • 相关阅读:
    Redis提供的持久化机制(RDB和AOF)
    linux创建子进程--fork()方法
    数据库-锁的实践
    nginx中,$request_uri和$uri的区别
    journal size
    目的:将两个三T的硬盘做成LVM(sdc,sdd)
    安装 rbbitMQ redis mongo的三个扩展
    MySQL server has gone away
    mysql创建utf-8字符集数据库
    Linux下杀毒软件clamav的安装和使用
  • 原文地址:https://www.cnblogs.com/ctlchild/p/5185336.html
Copyright © 2011-2022 走看看