zoukankan      html  css  js  c++  java
  • [BZOJ3700]发展城市 题解 [RMQ求LCA+分类讨论]

    BZOJ3700.发展城市

    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:

    1
    3
    1 2 1
    2 3 1
    3
    1 3 2
    3 1 1
    1 2 3
    

    Sample Output:

    2
    

    Hint:

    【数据规模】 1<=T<=20 1<=N<=10^5 0<=M<=10^3 1<=V<=10^6 1<=Z<=10^3

    题目分析:

    首先注意到M<=103,因此我们可以O(T*m2)判断两两顾客是否会碰面,而判断是否会碰面就是判断两人在树链的交上是否存在一个时间点处于同一个点(这个点可以在边上)。注意到T,m有点小大,因此我们需要O(nlogn)预处理,O(1)查询LCA。具体怎么做呢?

    First,我们dfs整棵树,求出每个点的dfs序和欧拉序(每遍历到一个点就把它记录下来,可重复),设两个点在欧拉序中最早出现的位置为L,R,那么两个点的LCA就是欧拉序中[L,R]之间的dfs序最大的点。既然如此,我们可以用st表预处理出两个位置之间dfs序最小的那个点,O(1)查询即可。

    Second,当我们能求出LCA后就需要大力分类讨论了

    我们设当前询问的两个顾客起点、终点、速度分别为s1,s2,t1,t2,v1,v2;

    lca1=LCA(s1,t1),lca2=LCA(s2,t2);

    lca3=LCA(s1,t2),lca4=LCA(s2,t1);

    lca5=LCA(s1,s2),lca6=LCA(t1,t2);

    1.s1=s2,此时肯定相交,ans++;

    2.lca3=lca4且dep[lca3]<dep[lca1]&&dep[lca3]<dep[lca2],如图:

    img

    此时两者树链的交为空,直接continue;

    -----------------------------------------------前------------方------------高------------能-----------------------------------------------------------

    判断完前两类之后,为了方便,我们另dep[lca1]>dep[lca2],即lca2是lca1的祖先;

    3.如果s2不在lca1的子树内且t2不在lca1的子树内,此时两者树链的交为空,直接continue

    4.如果lca1=lca2:

    (1)我们分别计算s1,s2到lca1的时间,如果时间相同 ans++; continue;

    (2)我们计算s1,s2到lca1上的路径的交,判断时间是否满足条件;

    (3)我们计算s1,t2到lca1上的路径的交,判断时间是否满足条件;

    (4)我们计算s2,t1到lca1上的路径的交,判断时间是否满足条件;

    (5)我们计算t1,t2到lca1上的路径的交,判断时间是否满足条件;

    5.如果s2在lca1的子树内:

    (1)我们分别计算s1,s2到lca1的时间,如果时间相同 ans++; continue;

    (2)我们计算s1,s2到lca1上的路径的交,判断时间是否满足条件;

    (3)我们计算t1,s2到lca1上的路径的交,判断时间是否满足条件;

    6.如果t2在lca1的子树内:

    (1)我们分别计算s1,s2到lca1的时间,如果时间相同 ans++; continue;

    (2)我们计算s1,t2到lca1上的路径的交,判断时间是否满足条件;

    (3)我们计算t1,t2到lca1上的路径的交,判断时间是否满足条件;

    详情见代码吧。。。

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 1005
    #define eps 1e-6
    #define LL long long
    using namespace std;
    int T,n,m,tot,num,lg[maxn<<1],pw[20],st1[20][maxn<<1],st2[20][maxn<<1],r[maxn],fst[maxn],a[maxn<<1],dep[maxn],f[maxn],dis[maxn],dfn[maxn],low[maxn],fir[maxn],nxt[maxn<<1],son[maxn<<1],w[maxn<<1],s[maxm],t[maxm],v[maxm];
    inline void add(int x,int y,int z){son[++tot]=y,nxt[tot]=fir[x],fir[x]=tot,w[tot]=z;}
    inline void dfs(int x){
        dep[x]=dep[f[x]]+1,dfn[x]=low[x]=++tot,r[tot]=x,fst[x]=++num,a[num]=x;st1[0][num]=dfn[x],st2[0][num]=x;
        for(register int i=fir[x];i;i=nxt[i]) if(son[i]!=f[x]) dis[son[i]]=dis[x]+w[i],f[son[i]]=x,dfs(son[i]),low[x]=max(low[x],low[son[i]]),a[++num]=x,st1[0][num]=dfn[x],st2[0][num]=x;
    }
    inline void get_st(){
        for(register int i=1;i<=17;i++) for(register int j=1;j<=num;j++) if(j+pw[i]>num) break;else 
        if(st1[i-1][j]>st1[i-1][j+pw[i-1]]) st1[i][j]=st1[i-1][j+pw[i-1]],st2[i][j]=st2[i-1][j+pw[i-1]];
        else st1[i][j]=st1[i-1][j],st2[i][j]=st2[i-1][j];
    }
    inline bool inside(int x,int y){return dfn[y]>=dfn[x]&&dfn[y]<=low[x];}//y在x子树内 
    inline int lca(int x,int y){x=fst[x],y=fst[y];if(x>y) swap(x,y);int len=y-x+1,t=lg[len];return (st1[t][x]<st1[t][y-pw[t]+1])?st2[t][x]:st2[t][y-pw[t]+1];}
    inline int read(){
        int ret=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
        while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
        return ret*f;
    }
    int main(){
        T=read();pw[0]=1;lg[0]=-1;for(register int i=1;i<=maxn*2-10;i++) lg[i]=lg[i>>1]+1;for(register int i=1;i<=17;i++) pw[i]=pw[i-1]*2;while(T--){
            memset(fir,0,sizeof(fir));tot=0,n=read();for(register int i=1,x,y,z;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
            tot=num=0,dfs(1);get_st();m=read();for(register int i=1;i<=m;i++) s[i]=read(),t[i]=read(),v[i]=read();
            int ans=0;for(register int i=1;i<=m;i++) for(register int j=i+1;j<=m;j++){
                if(s[i]==s[j]){ans++;continue;}int s1=s[i],s2=s[j],t1=t[i],t2=t[j],v1=v[i],v2=v[j],lca1=lca(s1,t1),lca2=lca(s2,t2),lca3=lca(s1,t2),lca4=lca(s2,t1),lca5=lca(s1,s2),lca6=lca(t1,t2);
                if(lca3==lca4&&dep[lca3]<dep[lca1]&&dep[lca3]<dep[lca2]) continue;
                if(dep[lca1]<dep[lca2]) swap(lca1,lca2),swap(lca3,lca4),swap(s1,s2),swap(t1,t2),swap(v1,v2);
                if(!inside(lca1,s2)&&!inside(lca1,t2)) continue;if(lca1==lca2){
                    LL tim1=1ll*(dis[s1]-dis[lca1])*v2,tim2=1ll*(dis[s2]-dis[lca1])*v1;if(tim1==tim2){ans++;continue;}
                    LL tim1l=1ll*(dis[s1]-dis[lca5])*v2,tim2l=1ll*(dis[s2]-dis[lca5])*v1;
                    LL tim1r=1ll*(dis[s1]-dis[lca1])*v2,tim2r=1ll*(dis[s2]-dis[lca1])*v1;
                    if(tim2l<=tim1l&&tim2r>=tim1r){ans++;continue;}if(tim1l<=tim2l&&tim1r>=tim2r){ans++;continue;}
                    tim1l=1ll*(dis[s1]-dis[lca3])*v2,tim2l=1ll*(dis[s2]-dis[lca1])*v1;
                    tim1r=1ll*(dis[s1]-dis[lca1])*v2,tim2r=1ll*(dis[s2]+dis[lca3]-2*dis[lca1])*v1;
                    if(tim2l<=tim1r&&tim2r>=tim1l){ans++;continue;}
                    tim1l=1ll*(dis[s1]-dis[lca1])*v2,tim2l=1ll*(dis[s2]-dis[lca4])*v1;
                    tim1r=1ll*(dis[s1]+dis[lca4]-2*dis[lca1])*v2,tim2r=1ll*(dis[s2]-dis[lca1])*v1;
                    if(tim1l<=tim2r&&tim1r>=tim2l){ans++;continue;}
                    tim1l=1ll*(dis[s1]-dis[lca1])*v2,tim2l=1ll*(dis[s2]-dis[lca1])*v1;
                    tim1r=1ll*(dis[s1]+dis[lca6]-2*dis[lca1])*v2,tim2r=1ll*(dis[s2]+dis[lca6]-2*dis[lca1])*v1;
                    if(tim2l<=tim1l&&tim2r>=tim1r){ans++;continue;}if(tim1l<=tim2l&&tim1r>=tim2r){ans++;continue;}continue;
                }
                if(inside(lca1,s2)){
                    LL tim1=1ll*(dis[s1]-dis[lca1])*v2,tim2=1ll*(dis[s2]-dis[lca1])*v1;if(tim1==tim2){ans++;continue;}
                    LL tim1l=1ll*(dis[s1]-dis[lca5])*v2,tim2l=1ll*(dis[s2]-dis[lca5])*v1;
                    LL tim1r=1ll*(dis[s1]-dis[lca1])*v2,tim2r=1ll*(dis[s2]-dis[lca1])*v1;
                    if(tim2l<=tim1l&&tim2r>=tim1r){ans++;continue;}if(tim1l<=tim2l&&tim1r>=tim2r){ans++;continue;}
                    tim1l=1ll*(dis[s1]-dis[lca1])*v2,tim2l=1ll*(dis[s2]-dis[lca4])*v1;
                    tim1r=1ll*(dis[s1]+dis[lca4]-2*dis[lca1])*v2,tim2r=1ll*(dis[s2]-dis[lca1])*v1;
                    if(tim1l<=tim2r&&tim1r>=tim2l){ans++;continue;}continue;
                }
                if(inside(lca1,t2)){
                    LL tim1=1ll*(dis[s1]-dis[lca1])*v2,tim2=1ll*(dis[s2]+dis[t2]-2*dis[lca2]-(dis[t2]-dis[lca1]))*v1;if(tim1==tim2){ans++;continue;}
                    LL tim1l=1ll*(dis[s1]-dis[lca3])*v2,tim2l=1ll*(dis[s2]+dis[t2]-2*dis[lca2]-(dis[t2]-dis[lca1]))*v1;
                    LL tim1r=1ll*(dis[s1]-dis[lca1])*v2,tim2r=1ll*(dis[s2]+dis[t2]-2*dis[lca2]-(dis[t2]-dis[lca3]))*v1;
                    if(tim2l<=tim1r&&tim2r>=tim1l){ans++;continue;}
                    tim1l=1ll*(dis[s1]-dis[lca1])*v2,tim2l=1ll*(dis[s2]+dis[t2]-2*dis[lca2]-(dis[t2]-dis[lca1]))*v1;
                    tim1r=1ll*(dis[s1]+dis[lca6]-2*dis[lca1])*v2,tim2r=1ll*(dis[s2]+dis[t2]-2*dis[lca2]-(dis[t2]-dis[lca6]))*v1;
                    if(tim2l<=tim1l&&tim2r>=tim1r){ans++;continue;}if(tim1l<=tim2l&&tim1r>=tim2r){ans++;continue;}
                }
            }
            cout<<ans<<'
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    xcode多target管理不同的环境(pod多target配置)
    OC与swift混编 #import "项目名-Swift.h"失效问题
    令人困惑的strtotime
    krpano 学习第一天
    git 全量同步分支
    MYSQL 什么时候用单列索引?什么使用用联合索引?
    _blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK} pip
    Mac php 装imagick扩展 菜鸟教程
    git仓库搬家
    文章简介 字符串截取
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14151133.html
Copyright © 2011-2022 走看看