码迷,mamicode.com
首页 > 其他好文 > 详细

刷题总结——road(ssoi)

时间:2017-07-22 16:42:48      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:map   dao   ade   次方   bvs   dmr   lbp   seed   while   

题目:

题目背景

SOURCE:NOIP2016-RZZ-1

题目描述

有 N 个城市,这些城市通过 M 条无向边互相连通,每条边有一个权值 Ci ,表示这条边的长度为 2^(Ci) ,没有两条边的长度是相同的。

设 d(i,j)为城市 i 到城市 j 的最短路长度,求:

    技术分享

答案以二进制输出。

输入格式

第一行,两个正整数 N ,M 。
接下来 M 行,每行三个正整数 Ai,Bi,Ci ,表示城市 Ai,Bi 间有一条权值为 Ci 的无向边。

输出格式

输出一个二进制数,表示所有无序点对间的最短路长度之和(即问题描述中的式子)。

样例数据 1

输入  [复制]

 

 

5 6 
1 3 5 
4 5 0 
2 1 3 
3 2 1 
4 3 4 
4 2 2

输出

1000100

备注

【样例解释】

技术分享

【数据规模与约定】
对于 30% 的数据,N,M≤50。
对于 60% 的数据,N,M≤100。
对于 80% 的数据,N≤2000;M≤10000。
对于 100% 的数据,1≤N≤105;1≤M≤2×105;1≤Ai,Bi≤N,Ai≠Bi,0≤Ci<M。

题解:

  首先可以看出要选的边的集合为最小生成树(边互不相等且为2的x次方可以推出),然后dfs计算每条边左右两边对应的size然后计算这条边对答案的贡献

  md忘记枚举边计算贡献这种操作了···

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int cnt=0,father[200005];
long long ans[500000];
int n,m,first[200010],next[500010],go[500010],w[500010],size[500010],tot=0;
inline int R()
{
  int i=0,f=1;char c;
  for(c=getchar();(c>9||c<0)&&c!=-;c=getchar());
  if(c==-)c=getchar(),f=-1;
  for(;c>=0&&c<=9;c=getchar())i=(i<<3)+(i<<1)+c-0;
  return i*f;
}
inline int getfather(int a)
{
  if(father[a]==a)  return a;
  father[a]=getfather(father[a]);
  return father[a];
}
inline void combfa(int a,int b)
{
  father[getfather(a)]=getfather(b);
}
struct node
{
  int from,go,val;
}edge[400005];
inline bool comp(node a,node b)
{
  return a.val<b.val;
}
inline void comb(int a,int b,int c)
{
  next[++tot]=first[a],first[a]=tot,go[tot]=b,w[tot]=c;
  next[++tot]=first[b],first[b]=tot,go[tot]=a,w[tot]=c;
}
inline void dfs(int u,int fa)
{
  size[u]=1;
  for(int e=first[u],v;e;e=next[e])
  {
    v=go[e];
    if(v==fa)  continue;
    dfs(v,u);
    size[u]+=size[v];
    ans[w[e]]+=(long long)size[v]*(n-size[v]);
    cnt=max(cnt,w[e]);
  }
}

void work()
{
    for(int i=0;i<=cnt;i++)
        if(ans[i]>1)ans[i+1]+=ans[i]/2,ans[i]%=2;
    int tmp=cnt+1;
    while(ans[tmp]>1)ans[tmp+1]+=ans[tmp]/2,ans[tmp++]%=2;
    cnt=tmp;
    for(int i=cnt;i>=0;i--)
        cout<<ans[i];    
}
int main()
{
  //freopen("roads.in","r",stdin);
  //freopen("roads.out","w",stdout);
  n=R(),m=R();     
  int a,b,c;
  for(int i=1;i<=n;i++)
    father[i]=i;
  for(int i=1;i<=m;i++)  
  {
      a=R();
      b=R();
      c=R();
      edge[i].from=a;
      edge[i].go=b;
      edge[i].val=c;
  }
  sort(edge+1,edge+m+1,comp);
  int cntt=0;
  for(int i=1;i<=m;i++) 
  {
    if(getfather(edge[i].from)!=getfather(edge[i].go))
    {
        combfa(edge[i].from,edge[i].go);
        cntt++;
        comb(edge[i].from,edge[i].go,edge[i].val);
    }
    if(cntt==n-1)  break;
  }
  dfs(1,0);
  work();
  return 0;
}

 

刷题总结——road(ssoi)

标签:map   dao   ade   次方   bvs   dmr   lbp   seed   while   

原文地址:http://www.cnblogs.com/AseanA/p/7221576.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!