• 【NOIP2013】货车运输


    感觉这题挺水的……真的挺水的……

    原题:

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

    0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

    思路非常简单,求最大生成树,然后剖,甚至连修改操作都没有

    这题水啊,二分就有60,正解就是个裸的生成树+剖

    如果NOIP考自己学过的比较高级的高级数据结构是一件挺好的事,受到NOIP难度的限制,考比较高级的东西的话就会裸得多,就没有呢么多魔性的东西了(然而因为选手水平提升而难度增加的概率非常大QAQ)

    有几点需要注意的地方,因为这里要用点的权值当边的权值,所以在路径遇到拐点(就是deep[x]>deep[y]<deep[z])的时候要特判一下,首先如果最后到一条重链上的时候x和y一样的话就不找了,因为这个点就是拐点,查找的话结果会是拐点和它的父节点之间的边,就跟路径没关系了,如果查找的话,查找左端点要是深度比较浅的内个点的标号+1,因为深度比较浅的内个点的值是它和它父节点之间连的边的值,但是在往同一个重链上攀的时候就不用这么判断了,因为不+1的话刚好把重链顶点和它的父节点之间的边算上了,就不用再算一遍了

    第一次写成树剖,这个东西终于懂了QAQ,收货还是挺多的

    代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 using namespace std;
      7 int read(){int z=0,mark=1;  char ch=getchar();
      8     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
      9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
     10     return z*mark;
     11 }
     12 struct ddd{int next,y,value;}e[1100000];int LINK[110000],ltop=0;
     13 inline void insert(int x,int y,int z){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].value=z;}
     14 struct ccc{int x,y,value;}tu[110000];int tltop=0;
     15 inline void insert_tu(int x,int y,int z){tu[++tltop].x=x,tu[tltop].y=y,tu[tltop].value=z;}
     16 struct dcd{int sleft,sright,mid,svalue;}tree[1100000];
     17 int n,m;
     18 int size[110000],deep[110000],father[110000],big_child[110000],top[11000];
     19 int dfs_xv[110000],fan_xv[110000],cnt=0,b_value[110000];
     20 int ji[110000];
     21 int group[110000],gtop=0;
     22 int cha(int x){  if(ji[x]==x)  return x;  ji[x]=cha(ji[x]);  return ji[x];}
     23 void bing(int x,int y){  int ji_x=cha(x),ji_y=cha(y);  ji[ji_x]=ji_y;}
     24 bool compare(ccc x,ccc y){  return x.value>y.value;}//这里求的是最大生成树
     25 void kruskal(){
     26     for(int i=1;i<=n;i++)  ji[i]=i;
     27     sort(tu+1,tu+tltop+1,compare);
     28     int _cnt=0;
     29     for(int i=1;i<=tltop;i++){
     30         int _x=cha(tu[i].x),_y=cha(tu[i].y);
     31         if(_x!=_y){
     32             bing(_x,_y);
     33             insert(tu[i].x,tu[i].y,tu[i].value),insert(tu[i].y,tu[i].x,tu[i].value);
     34             if(++_cnt==n-1)  return ;
     35         }
     36     }
     37 }
     38 void dfs1(int x,int _deep,int _father){
     39     group[x]=gtop;
     40     father[x]=_father,deep[x]=_deep,size[x]=1;
     41     int max_size=0,max_child=0;
     42     for(int i=LINK[x];i;i=e[i].next)if(e[i].y!=_father){
     43         dfs1(e[i].y,_deep+1,x);
     44         b_value[e[i].y]=e[i].value;
     45         size[x]+=size[e[i].y];
     46         if(size[e[i].y]>max_size){  max_size=size[e[i].y];  max_child=e[i].y;}
     47     }
     48     big_child[x]=max_child;
     49 }
     50 void dfs2(int x,int _top){
     51     top[x]=_top;  dfs_xv[++cnt]=x;  fan_xv[x]=cnt;
     52     if(big_child[x])  dfs2(big_child[x],_top);
     53     for(int i=LINK[x];i;i=e[i].next)if(e[i].y!=father[x] && e[i].y!=big_child[x])
     54         dfs2(e[i].y,e[i].y);
     55 }
     56 void get_SegmentTree(int x,int _left,int _right){
     57     tree[x].sleft=_left,tree[x].sright=_right,tree[x].mid=(_left+_right)>>1;
     58     if(_left==_right)  tree[x].svalue=b_value[dfs_xv[_left]];//注意这里
     59     else{
     60         get_SegmentTree(x<<1,_left,tree[x].mid),get_SegmentTree(x<<1|1,tree[x].mid+1,_right);
     61         tree[x].svalue=min(tree[x<<1].svalue,tree[x<<1|1].svalue);
     62     }
     63 }
     64 int search(int x,int _left,int _right){
     65     if(tree[x].sleft==_left && tree[x].sright==_right)  return tree[x].svalue;
     66     else if(_left<=tree[x].mid && _right>tree[x].mid)  return min(search(x<<1,_left,tree[x].mid),search(x<<1|1,tree[x].mid+1,_right));
     67     else if(_right<=tree[x].mid)  return search(x<<1,_left,_right);
     68     else  return search(x<<1|1,_left,_right);
     69 }
     70 int pa(int x,int y){
     71     int minn=999999999;
     72     int fa=top[x],fb=top[y];
     73     while(fa!=fb){
     74         if(deep[fa]<deep[fb])  swap(fa,fb),swap(x,y);
     75         minn=min(minn,search(1,fan_xv[fa],fan_xv[x]));//注意这里是x
     76         x=father[fa];  fa=top[x];
     77     }
     78     if(deep[x]>deep[y])  swap(x,y);
     79     if(x!=y)  minn=min(minn,search(1,fan_xv[x]+1,fan_xv[y]));//注意,如果不加判断会把拐点和拐点的父节点之间的连边也算进去,而且注意+1
     80     return minn;
     81 }
     82 int main(){//freopen("ddd.in","r",stdin);  freopen("ddd.out","w",stdout);
     83     memset(group,0,sizeof(group));
     84     cin>>n>>m;
     85     int _left,_right,_value;
     86     while(m --> 0){//趋向于
     87         _left=read(),_right=read(),_value=read();
     88         insert_tu(_left,_right,_value);
     89     }
     90     kruskal();
     91     for(int i=1;i<=n;i++)if(!group[i]){  b_value[i]=999999999;  gtop++,dfs1(i,1,0),dfs2(i,i);}//注意连通图问题
     92     get_SegmentTree(1,1,n);
     93     cin>>m;
     94     /*for(int i=1;i<=n;i++)  cout<<b_value[i]<<" ";
     95     cout<<endl;
     96     for(int i=1;i<=n;i++)  cout<<father[i]<<' ';
     97     cout<<endl;*/
     98     while(m --> 0){//趋向于
     99         _left=read(),_right=read();
    100         if(group[_left]==group[_right])  printf("%d
    ",pa(_left,_right));
    101         else  printf("-1
    ");
    102     }
    103     return 0;
    104 }
    View Code
  • 相关阅读:
    500. 键盘行
    657. 判断路线成圈
    771. 宝石与石头
    461. 汉明距离
    Java 基本数据类型
    Windows下的DOM操作
    jQuery学习笔记
    Java(16-19)
    Java(1-15)
    总结
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5900421.html
Copyright © 2020-2023  润新知