結果

問題 No.399 動的な領主
コンテスト
ユーザー ZeriToki
提出日時 2026-07-26 16:50:17
言語 C++23
(gcc 15.2.0 + boost 1.90.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 800 ms / 2,000 ms
+ 876µs
コード長 6,786 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 4,085 ms
コンパイル使用メモリ 363,620 KB
実行使用メモリ 30,096 KB
最終ジャッジ日時 2026-07-26 16:52:14
合計ジャッジ時間 11,854 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge3_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 19
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
template<typename T> bool chmin(T& a, T b){if(a > b){a = b; return true;} return false;}
template<typename T> bool chmax(T& a, T b){if(a < b){a = b; return true;} return false;}
const long long mod=998244353;
const long long mod2=469762049;
const long long mod100=1000000007;
struct HLD{
    //0-indexed
    //根が0の根付き木で実装
    vector<int>V;//入りがけ順
    vector<int>id;//頂点iがどこにあるか
    vector<int>head;//頂点iが属するheavy pathの親
    vector<int>child;//頂点iが属するheavy pathの子
    vector<vector<int>>G;//グラフ
    vector<int>subtree;//部分木サイズ
    vector<int>parent;

    //初期化
    HLD(int N){
        id.assign(N,-1);
        head.assign(N,-1);
        child.assign(N,-1);
        subtree.assign(N,-1);
        parent.assign(N,-1);
        G.assign(N,{});
    }

    //辺の追加
    void add_edge(int u,int v){
        G[u].push_back(v);
        G[v].push_back(u);
    }

    //テーブルの作成。辺を追加した後にやる
    void make_table(){
        auto dfs1=[&](auto &dfs1,int pos,int last)->void {
            subtree[pos]=1;
            for(auto nex:G[pos]){
                if(nex==last) continue;
                parent[nex]=pos;
                dfs1(dfs1,nex,pos);
                subtree[pos]+=subtree[nex];
            }
            return;
        };
        dfs1(dfs1,0,-1);
        auto dfs2=[&](auto &dfs2,int pos,int last,int h)->int {
            id[pos]=(int)V.size();
            V.push_back(pos);
            head[pos]=h;
            pair<int,int>priority={-1,-1};
            for(auto nex:G[pos]){
                if(nex==last) continue;
                chmax(priority,{subtree[nex],nex});
            }
            if(priority.second==-1){
                child[pos]=pos;
                return pos;
            }
            child[pos]=dfs2(dfs2,priority.second,pos,h);
            for(auto nex:G[pos]){
                if(nex==last) continue;
                if(priority.second==nex) continue;
                dfs2(dfs2,nex,pos,nex);
            }
            return child[pos];
        };
        dfs2(dfs2,0,-1,0);
        return;
    }
    int LCA(int u,int v){
        while(true){
            if(head[u]==head[v]){
                if(id[u]>id[v]) return v;
                else return u;
            }
            if(id[u]>id[v]){
                u=parent[head[u]];
            }
            else{
                v=parent[head[v]];
            }
        }
    }
};

template<typename T,typename F> struct lazysegtree{
    using F1=function<T(T,T)>;
    using F2=function<T(T,F)>;
    using F3=function<F(F,F)>;
    vector<T>node;
    vector<F>lazy;
    int N;int log;F1 op;T e;F2 mapping;F3 composition;F id;
    lazysegtree(int n,F1 op,T e,F2 mapping,F3 composition,F id)
    :op(op),e(e),mapping(mapping),composition(composition),id(id){
        N=1;
        log=1;
        while(N<n){
            N<<=1;
            log++;
        }
        node.assign(N*2,e);
        lazy.assign(N*2,id);
    }
    void set(int p,T x){
        int pos=1;
        for(int i=log-2;i>=0;i--){
            lazy[pos*2]=composition(lazy[pos*2],lazy[pos]);
            lazy[pos*2+1]=composition(lazy[pos*2+1],lazy[pos]);
            node[pos*2]=mapping(node[pos*2],lazy[pos]);
            node[pos*2+1]=mapping(node[pos*2+1],lazy[pos]);
            lazy[pos]=id;
            pos<<=1;
            if((p>>i)&1) pos++;
        }
        lazy[pos]=id;
        node[pos]=x;
        while(pos>=2){
            pos/=2;
            node[pos]=op(node[pos*2],node[pos*2+1]);
        }
        return;
    }
    void apply(int l,int r,int a,int b,int u,F f){
        if(b<=l || r<=a) return;
        if(l<=a && b<=r){
            lazy[u]=composition(lazy[u],f);
            node[u]=mapping(node[u],f);
            return;
        }
        lazy[u*2]=composition(lazy[u*2],lazy[u]);
        lazy[u*2+1]=composition(lazy[u*2+1],lazy[u]);
        node[u*2]=mapping(node[u*2],lazy[u]);
        node[u*2+1]=mapping(node[u*2+1],lazy[u]);
        lazy[u]=id;
        int m=(a+b)/2;
        apply(l,r,a,m,u*2,f);
        apply(l,r,m,b,u*2+1,f);
        node[u]=op(node[u*2],node[u*2+1]);
        return;
    }
    void apply(int l,int r,F f){//[l,r)を変更
        l++;r++;
        apply(l,r,1,N+1,1,f);
    }
    void apply(int p,F f){
        apply(p,p+1,1,N+1,1,f);
    }
    T fold(int l,int r,int a,int b,int u){
        if(b<=l || r<=a)return e;
        if(l<=a && b<=r){
            return node[u];
        }
        int m=(a+b)/2;
        T L=mapping(fold(l,r,a,m,u*2),lazy[u]);
        T R=mapping(fold(l,r,m,b,u*2+1),lazy[u]);
        return op(L,R);
    }
    T fold(int l,int r){//[l,r)をを求める
        l++;r++;
        return fold(l,r,1,N+1,1);
    }
    T fold(int p){
        p++;
        return fold(p,p+1,1,N+1,1);
    }
};

struct S{
    ll siz,ans;
};
S e(){
    S res;
    res.siz=0;
    res.ans=0;
    return res;
}
S op(S a,S b){
    S res;
    res.siz=a.siz+b.siz;
    res.ans=a.ans+b.ans;
    return res;
}
S mapping(S x,ll f){
    x.ans+=f*x.siz;
    return x;
}
ll composition(ll f,ll g){
    return f+g;
}
int main(){
    cout.tie()->sync_with_stdio(0);
    cin.tie(0);
    
    int N;cin>>N;
    int u[N-1],v[N-1];
    for(int i=0;i<N-1;i++){
        cin>>u[i]>>v[i];
        u[i]--;v[i]--;
    }
    int Q;cin>>Q;
    int A[Q],B[Q];
    for(int i=0;i<Q;i++){
        cin>>A[i]>>B[i];
        A[i]--;B[i]--;
    }


    HLD H(N);
    for(int i=0;i<N-1;i++){
        H.add_edge(u[i],v[i]);
    }
    H.make_table();
    lazysegtree<S,ll>seg(N,op,e(),mapping,composition,0LL);

    for(int i=0;i<N;i++){
        S now;
        now.siz=1;
        now.ans=1;
        seg.set(i,now);
    }


    auto solve=[&](int a,int b){
        ll res=0;
        int c=H.LCA(a,b);
        while(true){
            if(H.head[a]==H.head[c]){
                res+=seg.fold(H.id[c],H.id[a]+1).ans;
                seg.apply(H.id[c],H.id[a]+1,1);
                break;
            }
            int goal=H.head[a];
            res+=seg.fold(H.id[goal],H.id[a]+1).ans;
            seg.apply(H.id[goal],H.id[a]+1,1);
            a=H.parent[goal];
        }
        while(true){
            if(H.head[b]==H.head[c]){
                res+=seg.fold(H.id[c]+1,H.id[b]+1).ans;
                seg.apply(H.id[c]+1,H.id[b]+1,1);
                break;
            }
            int goal=H.head[b];
            res+=seg.fold(H.id[goal],H.id[b]+1).ans;
            seg.apply(H.id[goal],H.id[b]+1,1);
            b=H.parent[goal];
        }
        return res;
    };

    ll ans=0;
    for(int i=0;i<Q;i++){
        ans+=solve(A[i],B[i]);
    }
    cout<<ans<<endl;
}
0