刷题总结——货车运输

题目:

题目背景

NOIP2013 提高组 Day1 试题。

题目描述

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入格式

第一行有两个用一个空格隔开的整数 n ,m,表示 A 国有 n 座城市和 m 条道路。 
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。 
?接下来一行有一个整数 q,表示有 q 辆货车需要运货。 
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出格式

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出 -1。

样例数据 1

输入  [复制]

4 3 
1 2 4 
2 3 3 
3 1 1 

1 3 
1 4 
1 3

输出


-1 
3

备注

【数据范围】
对于 30% 的数据,0<n<1,000 ;0<m<10,000 ;0<q<1,000; 
对于 60% 的数据,0<n<1,000 ;0<m<50,000 ;0<q<1,000; 
对于 100% 的数据,0<n<10,000 ;0<m<50,000 ;0<q<30,000 ;0≤z≤100,000。

题解:

最大生成树然后在树上倍增就可以了···md并查集竟然打挂卡了我半天···

突然发现倍增法那么有用····

代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1e5+5;
const int M=5e5+5;
int R()
{
  int f=0;
  char c;
  for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
  for(;c>=‘0‘&&c<=‘9‘;c=getchar())
    f=(f<<3)+(f<<1)+c-‘0‘;
  return f;
}
int n,m,first[N],go[M],val[M],next[M],q,tot=0,g[N][35],deep[N],minn[N][35],father[N];
bool visit[N];
struct node
{
  int from;
  int go;
  int w;
}edge[M];
inline int getfa(int a)
{
  if(father[a]==a)  return a;
  else
  {
    father[a]=getfa(father[a]);
    return father[a];
  }
}
bool cmp(node a,node b)
{
  return a.w>b.w;
}
void comb(int a,int b,int c)
{
  next[++tot]=first[a],first[a]=tot,go[tot]=b,val[tot]=c;
  next[++tot]=first[b],first[b]=tot,go[tot]=a,val[tot]=c;
}
inline void dfs(int now,int fa)
{
  visit[now]=true;
  for(int e=first[now];e;e=next[e])
  {
    int v=go[e];
    if(v==fa||visit[v]==true)  continue;
    g[v][0]=now;
    minn[v][0]=max(val[e],minn[v][0]);
    deep[v]=deep[now]+1;
    dfs(v,now);
  }
}
inline int getans(int x,int y)
{
  int minx=1e+9,miny=1e+9,i,j;
  if(deep[x]<deep[y])  swap(x,y);
  for(i=0;(1<<i)<=deep[x];i++);
  i--;
  for(j=i;j>=0;j--)
  {
    if(deep[x]-(1<<j)>=deep[y])
    {
      minx=min(minx,minn[x][j]);
      x=g[x][j];
    }
  }
  if(x==y)  return minx;
  for(i=32;i>=0;i--)
  {
    if(g[x][i]!=g[y][i])
    {
      minx=min(minx,minn[x][i]);
      miny=min(miny,minn[y][i]);
      x=g[x][i];
      y=g[y][i];
    }
  }
  minx=min(minx,minn[x][0]);
  miny=min(miny,minn[y][0]);
  return min(minx,miny);
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R(),m=R();
  for(int i=1;i<=n;i++)
    father[i]=i;
  int x,y,z;
  for(int i=1;i<=m;i++)
  {
    x=R(),y=R(),z=R();
    edge[i].from=x;
    edge[i].go=y;
    edge[i].w=z;
  }
  sort(edge+1,edge+m+1,cmp);
  for(int i=1;i<=m;i++)
  {
    if(getfa(edge[i].from)!=getfa(edge[i].go))
    {
      father[getfa(edge[i].from)]=getfa(edge[i].go);
      comb(edge[i].from,edge[i].go,edge[i].w);
    }
  }
  for(int i=1;i<=n;i++)
  {
    if(!visit[i])
    {
      dfs(i,0);
      minn[i][0]=1e+9;
      g[i][0]=i;
    }
  }
  for(int i=1;i<=32;i++)
    for(int j=1;j<=n;j++)
    {
      g[j][i]=g[g[j][i-1]][i-1];
      minn[j][i]=min(minn[g[j][i-1]][i-1],minn[j][i-1]);
    }
  q=R();
  while(q--)
  {
    x=R(),y=R();
    if(getfa(x)!=getfa(y))  cout<<"-1"<<endl;
    else
      cout<<getans(x,y)<<endl;
  }
  return 0;
}
时间: 2024-10-03 14:45:09

刷题总结——货车运输的相关文章

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

7、8月刷题总结

准备开学了囧,7.8月刷题记录,以后好来复习,并且还要好好总结! 数据结构: splay: [BZOJ]1503: [NOI2004]郁闷的出纳员(Splay) [BZOJ]1269: [AHOI2006]文本编辑器editor(Splay) [BZOJ]1507: [NOI2003]Editor(Splay) treap: [BZOJ]1862: [Zjoi2006]GameZ游戏排名系统 & 1056: [HAOI2008]排名系统(treap+非常小心) [BZOJ]3224: Tyvj

倍增LCA NOIP2013 货车运输

货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条

noip2012~2015刷题小记录

2012d1t1 密码 模拟题 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 using nam

按算法刷题路线

搜索:八数码,生日蛋糕,靶形数独,(虫食算),最优贸易,引水入城,埃及分数,(p1189) dp:方格取数,树网的核,旅行路线 贪心:huffman,疫情控制 生成树:灾后重建,货车运输 连通块:间谍网络,星球大战 最短路:最优贸易,社交网络 最大流:地震逃生 区间:RMQ,区间连续和 数论:hank儿子题,解方程,虫食算,向量內积,斐波那契数列 字符串:阿里打印机

树上倍增——(货车运输 解题报告)

倍增新高度--树上倍增(其实差不多啦) 首先倍增就不说了 那么树上倍增和倍增有什么区别呢? 其实没什么区别,对于树上的结点u, 我们同样用st[u][l]数组记录其结点u向上2^l步数中权值最小(最大)的值 但是树上的边不是连续的啊,这我们怎么去维护呢? 这时,我们需要引入一个辅助数组f数组, 对于树上结点u,这个f数组f[u][l]表示这个点u向上走2^l次走到那个点 (这里有一个小技巧:把根的父亲设为根,防止跑到树的外面) 那么就很简单了,伪代码如下: for i:=1 to n do be

用js刷题的一些坑

leecode可以用js刷题了,我大js越来越被认可了是吧.但是刷题中会因为忽略js的一些特性掉入坑里.我这里总结一下我掉过的坑. 坑1:js中数组对象是引用对象 js中除了object还有数组对象也是引用对象,这点常常被忽视,所以在递归的时候传递数组要用arr.slice(0)这样复制一个一样的新数组,不然会出现你传入的数组会被同级的递归改变,结果就不对了. 所以只要数组复制的地方最好都要这么写,除非你真的想引用.而且注意是slice不是splice这两个方法差别很大,你如果用splice(0

LeetCode刷题之一:寻找只出现一次的数字

投简历的时候看到了个刷题网站,http://www.nowcoder.com/527604,就做了一套题,现记录下来. 题目为: Given an array of integers, every element appears twice except for one. Find that single one. Note: Your algorithm should have a linear runtime complexity. Could you implement it withou

【leetcode刷题笔记】Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers. For example, 1 / 2 3 T