P3241 [HNOI2015] 开店

为啥都是点分树大神。

我们考虑先按照 \(a\) 排序,然后分块。我们先对于每一个块开一个数组预处理出这块中的点对树中的每一个点的具体距离贡献之和。那么由距离公式,设 \(l(u,v)\) 表示最近公共祖先,\(d_u\) 表示 \(u\)\(1\) 的距离之和,那么对于答案 \(u\) 和块中点的集合 \(S\),拆成

\[|S|d_u+\sum_{v\in S}d_v-2\sum_{v\in S}d_{l(u,v)} \]

关键在于我们如何维护最后那个。考虑枚举最近公共祖先 \(x\),那么发现它会对它的子树 \(T_v\) 贡献 \(N_x-N_v\) 个值,其中 \(N_x\)\(x\) 子树中有多少个 \(S\) 中的值。

之后就是散块枚举用预处理 \(O(1)\) 求最近公共祖先做到 \(O(B)\)。那么时间复杂度就是 \(O(\frac{n^2}{B}+q(B+\frac{n}{B}))\),取 \(B=\sqrt{n}\) 平衡到 \(O(n\sqrt{n})\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=1.5e5+5;
const int B=400;
int n,Q,A;
pair<int,int>a[MAXN];
vector<pair<int,int>>adj[MAXN];
int st[MAXN][20],dfn[MAXN],dfntot,dep[MAXN],lg[MAXN],xl[MAXN];

void init(int u,int f){
    dfn[u]=++dfntot;
    xl[dfntot]=u;
    st[dfntot][0]=f;
    for(auto eg:adj[u]){
        int v=eg.first,w=eg.second;
        if(v==f){
            continue;
        }
        dep[v]=dep[u]+w;
        init(v,u);
    }    
}
#define gin(u,v) (dfn[u]<dfn[v]?u:v)
int lca(int u,int v){
    if(u==v){
        return u;
    }
    u=dfn[u],v=dfn[v];
    if(u>v){
        swap(u,v);
    }
    u++;
    int g=lg[v-u+1];
    return gin(st[u][g],st[v-(1<<g)+1][g]);
}
int sz[MAXN];
bool gd[MAXN];
ll dd[MAXN];
struct Kuai{
    int l,r;
    ll nm[MAXN];
    void init(){
        ll v=0;
        rep(i,l,r){
            v+=dep[a[i].second];
            gd[a[i].second]=true;
        }
        rep(i,1,n){
            nm[i]=v+1ll*(r-l+1)*dep[i];
            dd[i]=0;
        }
        for(int j=n;j>=1;--j){
            int u=xl[j];
            sz[u]=gd[u];
            for(auto eg:adj[u]){
                if(eg.first==st[j][0]){continue;}
                sz[u]+=sz[eg.first];
            }
        }
        rep(j,1,n){
            int u=xl[j];
            nm[u]-=(dd[u]+2ll*dep[u]*sz[u]);
            for(auto eg:adj[u]){
                if(eg.first==st[j][0]){continue;}
                dd[eg.first]=dd[u]+2ll*dep[u]*(sz[u]-sz[eg.first]);
            }
        }
        rep(i,l,r){
            gd[a[i].second]=false;
        }
    }
}k[MAXN/B+10];
ll la;
int id[MAXN];
ll ks(int l,int r,int u){
    ll ans=0;
    rep(j,l,r){
        int v=a[j].second;
        ans+=dep[u]+dep[v]-2*dep[lca(u,v)];
    }
    return ans;
}
pair<int,int>ga(int l,int r){
    return {min((la+l)%A,(la+r)%A),max((la+l)%A,(la+r)%A)};
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>Q>>A;
    rep(i,1,n){
        cin>>a[i].first;
        a[i].second=i;
    }
    rep(i,1,n-1){
        int u,v,w;
        cin>>u>>v>>w;
        adj[u].push_back({v,w});
        adj[v].push_back({u,w});
    }
    sort(a+1,a+n+1);
    int nb=(n+B-1)/B;
    rep(i,1,nb){
        k[i].l=k[i-1].r+1;
        k[i].r=k[i].l+B-1;
    }
    k[nb].r=n;
    rep(i,2,n){
        lg[i]=lg[i>>1]+1;
    }
    init(1,0);
    rep(j,1,lg[n]){
        rep(i,1,n-(1<<j)+1){
            st[i][j]=gin(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        }
    }
    rep(i,1,nb){
        k[i].init();
        rep(j,k[i].l,k[i].r){
            id[j]=i;
        }
    }
    rep(qq,1,Q){
        int l,r,u;
        cin>>u>>l>>r;
        pair<int,int>lx=ga(l,r);
        l=lx.first,r=lx.second;
        l=lower_bound(a+1,a+n+1,make_pair(l,0))-a,r=upper_bound(a+1,a+n+1,make_pair(r,n+1))-a-1;
        ll ans=0;
        if(id[l]==id[r]){
            ans=ks(l,r,u);
        }else{
            ans=ks(l,k[id[l]].r,u)+ks(k[id[r]].l,r,u);
            rep(i,id[l]+1,id[r]-1){
                ans+=k[i].nm[u];
            }
        }
        cout<<ans<<"\n";
        la=ans;
    }
    return 0;
}
posted @ 2025-12-25 21:56  tanghg  阅读(3)  评论(0)    收藏  举报