zoukankan      html  css  js  c++  java
  • 【BZOJ3700】发展城市 [LCA][RMQ]

    发展城市

    Time Limit: 20 Sec  Memory Limit: 512 MB
    [Submit][Status][Discuss]

    Description

      众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市。
      Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道。机智的Hzwer在宾馆中修建了N-1条隧道,也就是说,宾馆和隧道形成了一个树形结构。
      Hzwer有时候会花一天时间去视察某个城市,当来到一个城市之后,Hzwer会分析这些宾馆的顾客情况。对于每个顾客,Hzwer用三个数值描述他:(S, T, V)表示该顾客这天想要从宾馆S走到宾馆T,他的速度是V。
      Hzwer需要做一些收集一些数据,这样他就可以规划他接下来的投资。
      其中有一项数据就是收集所有顾客可能的碰面次数。
      每天清晨,顾客同时从S出发以V的速度前往T(注意S可能等于T),当到达了宾馆T的时候,顾客显然要找个房间住下,那么别的顾客再经过这里就不会碰面了。特别的,两个顾客同时到达一个宾馆是可以碰面的。同样,两个顾客同时从某宾馆出发也会碰面。

    Input

       第一行一个正整数T(1<=T<=20),表示Hzwer发展了T个城市,并且在这T个城市分别视察一次。
       对于每个T,第一行有一个正整数N(1<=N<=10^5)表示Hzwer在这个城市开了N个宾馆。
       接下来N-1行,每行三个整数X,Y,Z表示宾馆X和宾馆Y之间有一条长度为Z的隧道
       再接下来一行M表示这天顾客的数量。
       紧跟着M行每行三个整数(S, T, V)表示该顾客会从宾馆S走到宾馆T,速度为v

    Output

       对于每个T,输出一行,表示顾客的碰面次数。

    Sample Input

      2
      3
      1 2 1
      2 3 1
      3
      1 3 2
      3 1 1
      1 2 3
      1
      0

    Sample Output

      2
      0

    HINT

      1<=T<=20   1<=N<=10^5   0<=M<=10^3   1<=V<=10^6   1<=Z<=10^3

    Main idea

      给定若干个顾客,每个顾客会匀速从一个点走到另外一个点,问有几对人会在路上相遇。

    Solution

      由于人数较少,所以我们可以O(m^2)判断两人是否相交。

      首先,两个人相遇只可能是在路径重叠的部分相遇,所以我们先对两人的路径求交,这里提供一种对树上路径求交的方法:

        求出AB两人路径的交:
          设A路径为a.u->a.v,B路径为b.u->b.v。那么我们求出 LCA(a.u,b.u),LCA(a.v,b.v),LCA(a.u,b.v),LCA(b.u,a.v),然后保留下在AB路径上的点。(判断一个点是否在路径上若u在LCA(x,y)的子树中,且u为LCA(u,x)或者LCA(u,y),则u在路径x,y上),然后按照dfs序位置排序,去重,保留下后两个点,则后两个点即是路径的端点。

      但是这样求交的话需要多次查询LCA,我们用每次log的时间查询显然会超时,于是我们引进O(nlog(n))预处理,O(1)查询的LCA

        O(1)查询的LCA:
          我们先求出对于这棵树的欧拉序欧拉序:记下每个点第一次访问的位置以及回溯完的位置),然后我们用那么这时候x,y之间的LCA也就是 [pos[x],pos[y]] 区间内深度最小的点(pos[x]表示点x第一次在欧拉序中出现的位置),这个区间最小值RMQ求即可。

      现在我们已经求出了路径的交集,然后我们暴力分类讨论一下。如果没有交集则必然不相交,若交于一点判断一下到达时间即可,否则:

      先考虑两人运动的方向。我们记录p.u,p.v表示路径交集的两个端点。A1表示A到先进入路径的端点,A2表示A后到的端点,B1、B2类似(用距离长短判断即可),如果A1=B1则表示两人同向运动,否则表示相向运动。然后我们讨论一下:

        同向运动:如果两人同向运动,那么若先进入路径的后离开路径,则两人会相遇。
        相向运动:如果两人相向运动,则我们记录到端点的时间,如果两个人在路径上的时间有交集的话,则会相遇。

      然后这样判断一下就可以求出答案了,但是由于double定义下的除法速度很慢,会被卡常数,所以我们再用在long long定义下的交叉相乘来判断以上情况。这样我们就解决了这道题(≧▽≦)/

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>  
      7 using namespace std;
      8 typedef long long s64;
      9    
     10 const int ONE = 100005;
     11     
     12 int T;
     13 int n,m;
     14 int x,y,z;
     15 int next[ONE*2],first[ONE],go[ONE*2],w[ONE*2],tot;
     16 int pos[ONE],dfn_cnt,Dep[ONE],size[ONE];
     17 int MinD[ONE*2][18],NumD[ONE*2][18];
     18 int Log[ONE*2],Bin[18];
     19 int Stk[5],top,fc;
     20 int Ans;
     21 s64 d[ONE];
     22     
     23 struct power
     24 {
     25         int u,v;
     26         int val;
     27 }a[1005],p;
     28     
     29 namespace input
     30 {
     31         const int BufferSize = 1 << 16 | 1;
     32        
     33         char buffer[BufferSize];
     34         char *head = buffer + BufferSize;
     35         const char *tail = head;
     36        
     37         inline char nextChar()
     38         {
     39             if (head == tail)
     40             {
     41                 fread(buffer, 1, BufferSize, stdin);
     42                 head = buffer;
     43             }
     44             return *head++;
     45         }
     46        
     47         inline int get()
     48         {
     49             static char c;
     50             while ((c = nextChar()) < '0' || c > '9');
     51        
     52             int res = c - '0';
     53             while ((c = nextChar()) >= '0' && c <= '9')
     54                 res = res * 10 + c - '0';
     55             return res;
     56         }
     57 }
     58 using input::get;
     59     
     60 inline void Add(int u,int v,int z)
     61 {
     62         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  w[tot]=z;
     63         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  w[tot]=z;
     64 }
     65    
     66 namespace F
     67 {
     68         int Dfs(int u,int father)
     69         {
     70             pos[u] = ++dfn_cnt;
     71             Dep[u] = Dep[father] + 1;
     72             size[u] = 1;
     73             MinD[dfn_cnt][0]=Dep[u];    NumD[dfn_cnt][0]=u;
     74             for(int e=first[u];e;e=next[e])
     75             {
     76                 int v=go[e];
     77                 if(v==father) continue;
     78                 d[v] = d[u] + w[e];
     79                 Dep[v] = Dep[u] + 1;
     80                 Dfs(v,u);
     81                 size[u] += size[v];
     82                 MinD[++dfn_cnt][0]=Dep[u];  NumD[dfn_cnt][0]=u;
     83             }
     84         }
     85             
     86         inline void Pre_Rmq()
     87         {
     88             for(int j=1;j<=17;j++)
     89             for(int i=1;i<=dfn_cnt;i++)
     90             if(i+Bin[j]-1 <= dfn_cnt)
     91             {
     92                 int Next = i + Bin[j-1];
     93                 if(MinD[i][j-1] < MinD[Next][j-1])
     94                     MinD[i][j]=MinD[i][j-1], NumD[i][j]=NumD[i][j-1];
     95                 else
     96                     MinD[i][j]=MinD[Next][j-1], NumD[i][j]=NumD[Next][j-1];
     97             }
     98             else break;
     99         }
    100 }
    101   
    102 inline int LCA(int x,int y)
    103 {
    104         x=pos[x];   y=pos[y];
    105         if(x > y) swap(x,y);
    106         int T = Log[y - x +1];
    107         if(MinD[x][T] < MinD[y-Bin[T]+1][T]) return NumD[x][T];
    108         return NumD[y-Bin[T]+1][T];
    109 }
    110     
    111 inline s64 dist(int x,int y)
    112 {
    113         return d[x] + d[y] - (d[LCA(x,y)] << 1) ;
    114 }
    115     
    116 namespace PD
    117 {
    118         inline bool inroad(int u,power a)
    119         {
    120             int lca = LCA(a.u,a.v);
    121             if(LCA(u,lca) != lca) return 0;
    122             return (LCA(u,a.u)==u || LCA(u,a.v)==u);
    123         }
    124 }
    125     
    126 inline void Sort(int n)
    127 {
    128         for(int i=1;i<=n;i++)
    129         for(int j=i+1;j<=n;j++)
    130         if(pos[Stk[i]] > pos[Stk[j]])
    131             swap(Stk[i], Stk[j]);
    132 }
    133   
    134 inline power Get_road(power a,power b)
    135 {
    136         fc=top=0;
    137         Stk[++fc] = LCA(a.u,b.u);   Stk[++fc] = LCA(a.v,b.v);
    138         Stk[++fc] = LCA(a.u,b.v);   Stk[++fc] = LCA(b.u,a.v);
    139         for(int i=1;i<=fc;i++) 
    140         if(PD::inroad(Stk[i],a) && PD::inroad(Stk[i],b))
    141             Stk[++top] = Stk[i];
    142                     
    143         Sort(top);
    144         top=unique(Stk+1,Stk+top+1) - Stk - 1;
    145             
    146         power p;    p.val = 0;
    147         if(top==0)  p.u = p.v = 0;
    148         if(top==1)  p.u = p.v = Stk[1];
    149         if(top==2)  p.u=Stk[1], p.v=Stk[2];
    150         if(top==3)  p.u=Stk[2], p.v=Stk[3];
    151         return p;
    152 }
    153     
    154 inline bool pmin(s64 a,s64 b,s64 c)
    155 {
    156         if(a<=b && b<=c) return 1;
    157         return 0;
    158 }
    159     
    160 inline int Deal(int x,int y)
    161 {
    162         if(a[x].u == a[y].u) return 1;
    163         p = Get_road(a[x],a[y]);
    164         if(p.u==p.v)
    165         {
    166             if(!p.u) return 0;
    167             return (s64) dist(a[x].u,p.u) * a[y].val == (s64) dist(a[y].u,p.u) * a[x].val;
    168         }
    169             
    170         int A1,A2,B1,B2;
    171         double A1_time,A2_time,B1_time,B2_time; 
    172         if(dist(a[x].u,p.u) < dist(a[x].u,p.v)) A1=p.u, A2=p.v;else A1=p.v, A2=p.u;
    173         if(dist(a[y].u,p.u) < dist(a[y].u,p.v)) B1=p.u, B2=p.v;else B1=p.v, B2=p.u;
    174             
    175         A1_time=(s64)dist(A1,a[x].u)*a[y].val;   A2_time=(s64)dist(A2,a[x].u)*a[y].val;
    176         B1_time=(s64)dist(B1,a[y].u)*a[x].val;   B2_time=(s64)dist(B2,a[y].u)*a[x].val;
    177             
    178         if(A1==B1)//same
    179         {
    180             if(A1_time == B1_time) return 1;
    181             if(A1_time < B1_time) return A2_time >= B2_time;
    182             return A2_time <= B2_time;
    183         }
    184         else
    185         {
    186             if(pmin(A1_time,B1_time,A2_time)) return 1;
    187             if(pmin(A1_time,B2_time,A2_time)) return 1;
    188             if(pmin(B1_time,A1_time,B2_time)) return 1;
    189             if(pmin(B1_time,A2_time,B2_time)) return 1;
    190             return 0;
    191         }
    192 }
    193     
    194 inline void Solve()
    195 {       
    196         n=get();
    197         dfn_cnt=tot=0;
    198         memset(first,0,sizeof(first));
    199         for(int i=1;i<n;i++)
    200         {
    201             x=get();    y=get();    z=get();
    202             Add(x,y,z);
    203         }
    204             
    205         F::Dfs(1,0);    F::Pre_Rmq();
    206             
    207         m=get();
    208         for(int i=1;i<=m;i++)
    209         {
    210             a[i].u=get();   a[i].v=get();   a[i].val=get();
    211         }
    212             
    213         Ans = 0;
    214         
    215         for(int i=1;i<=m;i++)
    216         for(int j=i+1;j<=m;j++)
    217         {
    218             Ans += Deal(i,j);
    219         }
    220           
    221         printf("%d
    ",Ans);
    222 }
    223     
    224 int main()
    225 {      
    226         Log[0]=-1;  for(int i=1;i<=2e5;i++) Log[i] = Log[i>>1] + 1;
    227         Bin[0]=1;   for(int i=1;i<=17; i++) Bin[i] = Bin[i-1] << 1;
    228             
    229         T=get();
    230             
    231         while(T--)
    232             Solve();
    233 }
    View Code
  • 相关阅读:
    Unix/Linux环境C编程入门教程(20) 搭建基于Mac的 Xcode 与 QT 开发环境
    CC++初学者编程教程(10) 搭建Android java C/C++ NDK QTforAndroid 开发环境
    CC++初学者编程教程(9) Windows8.1安装VS2013并捆绑QT与编程助手
    CC++初学者编程教程(8) VS2013配置编程助手与QT
    云服务和虚拟机的预留 IP 地址
    zabbix自定义监控mysql
    关于 /etc/zabbix/zabbix_agentd.conf 文件 Hostname 文件的说明
    Centos7安装Zabbix3.4
    覆盖索引小结
    关于使用索引的一些经验
  • 原文地址:https://www.cnblogs.com/BearChild/p/6531428.html
Copyright © 2011-2022 走看看