zoukankan      html  css  js  c++  java
  • 【树】【积累】Waterloo2019ICPC D.Deliveries (整除分块+树分块+括号序)

    题解:Waterloo2019ICPC D.Deliveries (整除分块+树分块+括号序)

    题目链接:cf Waterloo2019ICPC D.Deliveries

    题意:

    一棵 (N) 个顶点的带边权无根树,(Q) 个询问。每次询问 (S;F;T) ,表示从点 (S) 到点 (F) 用容量为 (T) 的电池前进,全程总共需要停下来多少次 。对于每个询问输出一行一个整数。

    电池每当用完时,必须立刻停下来充电,后才能继续前进;每到达一个顶点必须停下来一次,停下来的这一次也可以用来充电。起点和终点需要各算一次停止次数。

    时限:4s;空限:256MB。

    数据范围:(1le N,Qle100000) , (1le w,Tle20000)

    样例:

    input

    7 5
    1 2 1
    2 3 2
    2 4 3
    4 5 4
    4 6 5
    4 7 6
    3 7 2
    2 6 1
    5 7 3
    1 4 1
    3 7 1
    

    output

    7
    9
    5
    5
    12
    

    input

    4 3
    1 2 5
    2 3 10
    3 4 20
    1 4 20
    1 4 10
    1 4 5
    

    output

    4
    5
    8
    

    伪标程:(抄标程,改一下代码风格,加一些注释)

    #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=5e5+5;
    
    int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
    inline void add(int u,int v){
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    int din[maxn],dout[maxn],tnt,f[maxn][25];
    void dfs(int u,int fa)
    {
        din[u]=++tnt;f[u][0]=fa;
        for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
        for(int i=head[u];i;i=nxt[i])
            if(to[i]!=fa)dfs(to[i],u);
        dout[u]=++tnt;
    }
    inline bool upper(int u,int v){
        return din[u]<=din[v]&&dout[u]>=dout[v];
    }
    int LCA(int u,int v)
    {
        if(upper(u,v))return u;
        for(int i=20;i>=0;i--)
            if(!upper(f[u][i],v))u=f[u][i];
        return f[u][0];
    }
    struct EG{
        int u,v;
    }eg[maxn];
    const int MAXN=2e4+5;
    const int K=512;
    struct Qu{
        int u,v,id;
    };vector<Qu>qu[MAXN];
    int *C[maxn];
    int siz[maxn],dis[maxn],S[maxn],A[maxn];ll res[maxn];
    ll cal(int l,int r)
    {
        ll res=0;
        while(l<=r)
        {
            if(l%K==0&&l+K-1<=r){
                res+=S[l/K];l+=K;
            }
            else res+=A[l++];
        }
        return res;
    }
    int main()
    {
        int n,q,u,v,w;
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v);add(v,u);eg[i]={u,v};
            w--;
            dis[i]=w;
            for(int l=1,r;l<=w;l=r+1){
                siz[l]++;r=w/(w/l);
            }
            siz[w+1]++;
        }
        for(int i=0;i<MAXN;i++)C[i]=new int[siz[i]+1];
        mem(siz,0);
        for(int i=1;i<=n-1;i++)C[1][siz[1]++]=i;
        dfs(1,1);
        for(int i=1;i<=q;i++){
            scanf("%d%d%d",&u,&v,&w);
            qu[w].push_back({u,v,i});
        }
        for(int i=1;i<=n-1;i++)if(din[eg[i].u]>din[eg[i].v])swap(eg[i].u,eg[i].v);
        for(int c=1;c<MAXN;c++)//枚举T
        {
            for(int i=0;i<siz[c];i++)
            {
                int id=C[c][i];//边的id
                int val=dis[id]/c;
                if(val){
                    int cc=dis[id]/val+1;
                    /*
                     在区间cc=[c,dis/(dis/c)]这个区间内,
                     dis/cc的值是一样的,都是 (val=dis/c)+1
                     */
                    C[cc][siz[cc]++]=id;
                }
                val++;
                S[din[eg[id].v]/K]+=(val-A[din[eg[id].v]]);A[din[eg[id].v]]=val;
                S[dout[eg[id].v]/K]+=(-val-A[dout[eg[id].v]]);A[dout[eg[id].v]]=-val;
                /*
                 此时 在块[id/K]里边更新块值和, 同时记录单点答案
                 在求值时,当[l,r]的距离大于K时,不断加上块和,
                 直到[l,r]距离小于K,再遍历累加单点值
                 */
            }
            delete[] C[c];
            for(Qu qq:qu[c]){
                u=LCA(qq.u,qq.v);
                res[qq.id]=cal(din[u]+1,din[qq.u])+cal(din[u]+1,din[qq.v]);
            }
        }
        for(int i=1;i<=q;i++)printf("%lld
    ",res[i]+1);
    }
    


    叨叨:

    T^T 这道题的做法对我来说真的是太难想到了。看标程的时候都 险些看不懂。

  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/kkkek/p/13661653.html
Copyright © 2011-2022 走看看