• P2993 [FJOI2014]最短路径树问题 点分治+最短路


     这道题还是非常简单的,由于我们要保证最小字典序,因此我们需要把边进行排序,然后从大到小插入,因为链式前向星是倒着存的。我们只需要先跑一个最短路,然后查询边是不是在最短路上,这个可以通过枚举边并用

    dist[v]=dist[u]+edge[i]判断即可,如果是的话我们在这个边上打上标记。并进行一次DFS打上标记,保证是一颗树。

    然后就简单了,直接点分治查询子树链的长度和节点个树。然后就很更新保存即可,这个查询其实和上个题很相似,用一个mp保存点的个数对应的最长的链,这样就能在枚举子树的链的节点个数的时候,查询是否有其他子树的节点个数,和当前节点的链组成一条合法的链。

    。。。为毛找重心在外面开一个maxlink,维护内部最长链会错。。。开数组维护每个节点就不会。。。真奇怪。。。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define pii pair<int,int>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int maxx = 2e5+6;
    struct edge{
      int v,w,next,use;
    }e[maxx];
    int tot,root,n,m,k,l,r,size,ans,ans1;
    int sz[maxx],vis[maxx],head[maxx],dis[maxx],id[maxx],q[maxx];
    int d[maxx],mp[maxx],cnt[maxx],mx[maxx];
    struct node{
       int u,v,w;
    }edge[maxx];
    struct que{
      int len,k;
    }que[maxx];
    void add(int x,int y,int z){
       e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
       e[++tot].v=x;e[tot].w=z;e[tot].next=head[y];head[y]=tot;
    }
    void dfs(int x){
       vis[x]=1;
       for (int i=head[x];i;i=e[i].next){
          int v=e[i].v;
          if (e[i].use==1 && !vis[v]){
              e[i].use=e[i^1].use=2;
              dfs(v);
          }
       }
    }
    void dji(){
       priority_queue<pii>q;
       for (int i=1;i<=n;i++){
           dis[i]=INF;
       }
       dis[1]=0;
       q.push(make_pair(0,1));
       while(q.size()){
          int u=q.top().second;
          q.pop();
          if (vis[u])continue;
          vis[u]=1;
          for (int i=head[u];i;i=e[i].next){
              int v=e[i].v;
              if (dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                q.push(make_pair(-dis[v],v));
              }
          }
       }
       for (int i=2;i<=tot;i++){
         int u=e[i^1].v;
         int v=e[i].v;
         if (dis[v]==dis[u]+e[i].w){
             e[i].use=1;
         }
       }
       memset(vis,0,sizeof(vis));
       dfs(1);
    }
    void getroot(int x,int fa)
    {
        sz[x]=1;mx[x]=0;
        for (int i=head[x];i;i=e[i].next)
        {
            if (e[i].use<2||vis[e[i].v]||e[i].v==fa) continue;
            getroot(e[i].v,x);
            sz[x]+=sz[e[i].v];
            mx[x]=max(mx[x],sz[e[i].v]);
        }
        mx[x]=max(mx[x],size-sz[x]);
        if (!root||mx[x]<mx[root]) root=x;
    }
    void getdis(int u,int num,int dist,int fa)
    {
        //cout<<u<<"orz"<<num<<endl;
        if (num<=k)que[++r].k=num,que[r].len=dist;
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;
        //    cout<<v<<" "<<e[i].use<<" "<<vis[v]<<" "<<fa<<" "<<num<<endl;
            if (e[i].use<2 || vis[v] || v==fa)continue;
            getdis(v,num+1,dist+e[i].w,u);
        }
    }
    void slove(int u){
        vis[u]=1;
        r=0;
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if (e[i].use<2||vis[v])continue;
            int tmp=r;
            getdis(v,1,e[i].w,u);
            for (int j=tmp+1;j<=r;j++)
            {
                int dist=que[j].len;
                int num=que[j].k;
                if (mp[k-num]>-1)
                {
                    if (dist+mp[k-num]>ans)ans=dist+mp[k-num],ans1=cnt[k-num];
                    else if (dist+mp[k-num]==ans)ans1+=cnt[k-num];
                }
            }
            for (int j=tmp+1;j<=r;j++)
            {
               int num=que[j].k,dist=que[j].len;
               if (dist>mp[num])mp[num]=dist,cnt[num]=1;
               else if (dist==mp[num])cnt[num]++;
            }
        }
        while(r)mp[que[r].k]=-1,cnt[que[r].k]=0,r--;
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if (e[i].use<2||vis[v])continue;
            root=0;
            size=sz[v];
            getroot(v,u);
            slove(root);
        }
    }
    bool cmp(node a,node b){
       if (a.u==b.u){
          if (a.v==b.v){
              return a.w<b.w;
          }
          return a.v<b.v;
       }
       return a.u<b.u;
    }
    int main(){
      scanf("%d%d%d",&n,&m,&k);
      k--;
      for (int i=1;i<=m;i++){
          scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
      }
      sort(edge+1,edge+1+m,cmp);
      tot=1;
      memset(cnt,0,sizeof(cnt));
      memset(head,0,sizeof(head));
      for (int i=m;i>=1;i--){
         add(edge[i].u,edge[i].v,edge[i].w);
      }
      dji();
      memset(vis,0,sizeof(vis));
      root=0;
      size=n;
      getroot(1,0);
      for (int i=1;i<=k;i++)mp[i]=-1;
      cnt[0]=1;
      slove(root);
      printf("%d %d
    ",ans,ans1);
      return 0;
    }
    

      

  • 相关阅读:
    算法分析之最小子段求和
    算法分析之最大子段求和(二)
    算法分析之爬楼梯问题
    .net编码规则
    tensorflow mnist
    The tensorflow simplest calculate
    python opencv
    english
    opencv 图片识别
    随机概率
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11574851.html
Copyright © 2020-2023  润新知