題解 運輸 樹狀數組+乘除分塊+離線差分

題解 運輸

題目描述

KzFSHS.png

KzizB8.png

具體做法與心路歷程

一開始沒想到正解,於是開始碼O(mw)O(mw)的暴力,碼暴力的時候發現了正解。

具體做法

考慮將詢問離線下來,然後差分到樹上,暴力的方法就是在dfsdfs樹的時候用一個數組ans[i]ans[i]表示從根走到當前節點,

經過的邊在詢問的電量爲ii時所需要的最少次數。那麼在dfsdfs時從對每個ans[i]ans[i]維護一下即可。

正解即是對於某條邊ww,我們發現它對ansans的答案是可以整除分塊的,那麼我們用樹狀數組維護ansans,整除分開統計即可。

時間複雜度爲O(mwlogw)O(m\sqrt{w}logw)

Code\mathcal{Code}

/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年11月04日 星期一 08時30分26秒
*******************************/
#include<cstdio>
#include<algorithm>
#include<vector>
#define int long long 

using namespace std;

struct IO{
    template<typename T>
    IO & operator>>(T&res)
    {
        T q=1;char ch;
        while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
        res=(ch^48);
        while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
        res*=q;
        return *this;
    }
}cin;

struct edge{
    int to,next,w;
    edge(int a=0,int b=0,int c=0):to(a),next(b),w(c){}
};

struct Node{
    int id,q,w;
    Node(int a=0,int b=0,int c=0):id(a),q(b),w(c){}
};

const int maxn=1e5+10;
const int LG=20;
const int LIM=3e4;

int n,m,head[maxn],cnt,s[maxn],prime[maxn],tot,ans[maxn],f[maxn][LG+1],depth[maxn];
bool vis[maxn];
edge e[maxn<<1];
vector<Node>V[maxn];

/*{{{BIT*/

namespace BIT{

    int tr[31000];

    void add(int x,int val)
    {
        while(x<=LIM)
        {
            tr[x]+=val;
            x+=x&-x;
        }
    }

    int sum(int x)
    {
        int res=0;
        while(x)
        {
            res+=tr[x];
            x-=x&-x;
        }
        return res;
    }

};

/*}}}*/

void add(int u,int v,int w)
{
    e[++cnt]=edge(v,head[u],w);
    head[u]=cnt;
}

void pre_dfs(int now)
{
    depth[now]=depth[f[now][0]]+1;
    for(int i=1;i<=LG;i++)
        f[now][i]=f[f[now][i-1]][i-1];
    for(int i=head[now];i;i=e[i].next)
        if(e[i].to!=f[now][0])
        {
            f[e[i].to][0]=now;
            pre_dfs(e[i].to);
        }
}

int LCA(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=LG;i>=0;i--)
        if(depth[f[x][i]]>=depth[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=LG;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}

void update(int w,int q)
{
    w--;
    int d;
    for(int l=1,r;l<=w;l=r+1)
    {
        r=w/(w/l);
        d=w/l;
        BIT::add(l,d*q);
        BIT::add(r+1,d*q*(-1));
    }
}

void dfs(int now)
{
    int w,id,q;
    for(int i=0;i<(int)V[now].size();i++)
    {
        w=V[now][i].w,id=V[now][i].id,q=V[now][i].q;
        ans[id]+=q*BIT::sum(w);
    }
    for(int i=head[now];i;i=e[i].next)
        if(e[i].to!=f[now][0])
        {
            w=e[i].w;
            update(w,1);
            dfs(e[i].to);
            update(w,-1);
        }
}

signed main()
{
    //freopen("delivery.in","r",stdin);
    //freopen("delivery.out","w",stdout);
    cin>>n>>m;
    int u,v,w;
    for(int i=1;i<n;i++)
    {
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    pre_dfs(1);
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v>>w;
        if(u==v){ ans[i]=0; continue; }
        ans[i]=depth[u]+depth[v]-2*depth[LCA(u,v)]+1;
        V[u].push_back(Node(i,1,w));
        V[v].push_back(Node(i,1,w));
        V[LCA(u,v)].push_back(Node(i,-2,w));
    }
    dfs(1);
    for(int i=1;i<=m;i++)
    {
        if(ans[i]==0) ans[i]=1;
        printf("%lld\n",ans[i]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章