結果

問題 No.3193 Submit Your Solution
ユーザー GOTKAKO
提出日時 2025-06-28 12:44:52
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
RE  
実行時間 -
コード長 12,265 bytes
コンパイル時間 3,912 ms
コンパイル使用メモリ 262,084 KB
実行使用メモリ 168,556 KB
最終ジャッジ日時 2025-06-28 12:45:11
合計ジャッジ時間 18,846 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other RE * 1 TLE * 1 -- * 15
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
using ull = unsigned long long;

template <typename T>
class SparseTable{
    private:
    T op(T a,T b){return min(a,b);} //条件op(A,A)=A &op(op(A,B),C)=op(A,op(B,C));
    T e(T a,T b){return {1001001001,-1};}
    array<int,400000> check;
    array<array<T,400000>,19> table;
    public:
    void make(const vector<T> &A){
        int n = A.size();
        int p2 = 1,l = 0;
        for(int i=1; i<400000; i++){
            if(i == p2) check[i] = l,l++,p2 *= 2;
            else check[i] = check[i-1];
        }
        for(int i=0; i<n; i++) table[0][i] = A[i];
        for(int i=n; i<400000; i++) table[0][i] = {1001001001,-1};
        l = 1;
        for(int i=2; i<=n; i*=2,l++){
            for(int k=0; k<=n-i; k++) table[l][k] = op(table[l-1][k],table[l-1][k+(i>>1)]);
            for(int k=n-i+1; k<400000; k++) table[l][k] = {1001001001,-1};
        }
    }
    T rangeans(int l,int r){//[L,R)だよ.
        int pos = check[r-l]; r -= 1<<pos;
        return op(table[pos][l],table[pos][r]);
    }
};
class LCA{
    private:
    SparseTable<pair<int,int>> ST;
    public:
    vector<int> in,out;
    vector<ull> dist;
    void make1(const vector<int> &P){// p0=-1でp1以降だけ
        int r = 0;
        vector<vector<int>> G(P.size()+1);
        for(int i=0; i<P.size(); i++) G.at(P.at(i)).push_back(i+1); 
        make3(G,r);
    }
    void make2(const vector<int> &P){//pi=-1 iは固定されていない.
        int r = -1;
        vector<vector<int>> G(P.size());
        for(int i=0; i<P.size(); i++){
            if(P.at(i) == -1) r = i;
            else G.at(P.at(i)).push_back(i);
        }
        make3(G,r);
    }
    void make3(const vector<vector<int>> &Graph,int root){ //直接グラフを渡す.
        int t = 0,dep = 0,n = Graph.size(),pos = root;
        dist.resize(n),in.resize(n),out.resize(n);
 
        vector<pair<int,int>> depth;
        vector<int> Itr(n,-1),P(n,-1);
        while(pos != -1){
            depth.push_back({dep,pos});
            if(++Itr.at(pos) == 0) in.at(pos) = t;
            int to = P.at(pos);
            if(Itr.at(pos) == Graph.at(pos).size()) out.at(pos) = ++t;
            else{
                to = Graph.at(pos).at(Itr.at(pos));
                if(to == P.at(pos)){
                    Itr.at(pos)++;
                    if(Itr.at(pos) == Graph.at(pos).size()) out.at(pos) = ++t;
                    else to = Graph.at(pos).at(Itr.at(pos));
                }
            }
            if(to != P.at(pos)) dist.at(to) = dist.at(pos)+1,P.at(to) = pos,t++,dep++;
            else dep--;
            pos = to;
        }
        ST.make(depth);
    }
    int lca(int u,int v){
        int tu = in.at(u),tv = in.at(v);
        if(tu > tv) swap(tu,tv);
        return ST.rangeans(tu,tv+1).second;
    }
    int twodist(int u,int v){return dist.at(u)+dist.at(v)-2*dist.at(lca(u,v));}
    int onedist(int u){return dist.at(u);} 
    pair<vector<int>,vector<int>> getinout(){return {in,out};}
};

LCA L;
int in[200000],out[200000];
vector<pair<int,int>> in2;
pair<vector<vector<int>>,vector<vector<vector<int>>>> AuxiliaryTree(const vector<int> &A,int maxa){
    //色ごとに木を構築するやつ O(NlogN) 定数悪い実装.
    //return {色ごとの実際の頂点番号,色ごとのTree}
    //重み付きだったら修正必須.
    int N = A.size();
    vector<vector<int>> ret1(maxa);
    for(auto [t,i] : in2) if(A.at(i) != -1) ret1.at(A.at(i)).emplace_back(i);

    for(auto &as : ret1){
        int n = as.size();
        for(int i=0; i<n-1; i++){
            int pos1 = as.at(i),pos2 = as.at(i+1);
            int pos3 = L.lca(pos1,pos2);
            assert(pos3 != -1);
            as.emplace_back(pos3);
        }
        sort(as.begin(),as.end(),[&](auto &a,auto &b){return in[a]<in[b];});
        as.erase(unique(as.begin(),as.end()),as.end());
    }

    vector<vector<vector<int>>> ret2(maxa);
    for(int i=0; i<maxa; i++){
        int siz = ret1.at(i).size();
        ret2.at(i).resize(siz);
        stack<pair<int,int>> st;
        for(int k=0; k<siz; k++){
            int pos = ret1.at(i).at(k),out1 = out[pos];
            while(st.size()){
                auto[bk,out2] = st.top();
                if(out1 < out2){
                    ret2.at(i).at(bk).emplace_back(k);
                    ret2.at(i).at(k).emplace_back(bk);
                    break;
                } 
                else st.pop();
            }
            st.push({k,out1});
        }
    }
    return{ret1,ret2};
}

tuple<ull,ull,ull,ull> V[200000];
ull dist2[200000];

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int N; cin >> N;
    //if(N != 199910) return 0;
    vector<vector<int>> Graph(N);
    for(int i=0; i<N-1; i++){
        int u = i,v = i+1;
        cin >> u >> v,u--; v--;
        Graph.at(u).push_back(v);
        Graph.at(v).push_back(u);
    }
    vector<int> To((N-1)*2),start(N+1);
    {
        int point = 0;
        for(int i=0; i<N; i++){
            start.at(i) = point;
            for(auto to : Graph.at(i)) To.at(point++) = to;
            Graph.at(i).clear();
        }
        start.back() = point;
    }

    for(int i=0; i<N-1; i++){
        int u = i,v = i+1;
        cin >> u >> v,u--; v--;
        Graph.at(u).push_back(v);
        Graph.at(v).push_back(u);
    }

    L.make3(Graph,0);
    for(int i=0; i<N; i++) in[i] = L.in.at(i),out[i] = L.out.at(i),dist2[i] = L.dist.at(i);
    in2.resize(N);
    for(int i=0; i<N; i++) in2.at(i) = {in[i],i};
    sort(in2.begin(),in2.end());

    ull answer = 0;
    vector<bool> stop(N);    
    auto findsiz = [&](int s) -> int {
        stack<tuple<int,int,int,int>> st;
        st.push({1,s,start.at(s),-1});
        int bring = 0;
        while(st.size()){
            auto &[vs,pos,i,back] = st.top();
            vs += bring; bring = 0;
            while(true){
                if(i == start.at(pos+1)){bring = vs; st.pop(); break;}
                int to = To.at(i); i++;
                if(stop.at(to) || to == back) continue;
                st.push({1,to,start.at(to),pos}); break;
            }
        }
        return bring;
    };
    auto centroid = [&](int s,int siz) -> int {
        stack<tuple<int,int,int,int,bool>> st;
        st.push({1,s,start.at(s),-1,true});
        int bring = 0;
        while(st.size()){
            auto &[vs,pos,i,back,ok] = st.top();
            if(bring > siz/2) ok = false;
            vs += bring; bring = 0;
            while(true){
                if(i == start.at(pos+1)){
                    bring = vs;
                    if(siz-bring <= N/2 && ok) return pos;
                    st.pop(); break;
                }
                int to = To.at(i); i++;
                if(stop.at(to) || to == back) continue;
                st.push({1,to,start.at(to),pos,true}); break;
            }
        }
        return -1;
    };
    vector<int> Ps = {0};

    while(Ps.size()){
        for(auto &p : Ps){
            int siz = findsiz(p);
            if(siz != 1) p = centroid(p,siz);
            else stop.at(p) = true,p = -1;
        }

        vector<int> C1(N,-1),C2(N,-1);
        int cpos1 = 0,cpos2 = 0;
        
        for(auto &p : Ps){
            if(p == -1) continue;
            auto dfs = [&](int s,int b) -> void {
                stack<tuple<int,int,int>> st;
                st.push({s,start.at(s),b});
                C1.at(s) = cpos1,C2.at(s) = cpos2;
                while(st.size()){
                    auto &[pos,i,back] = st.top();
                    while(true){
                        if(i == start.at(pos+1)){st.pop(); break;}
                        int to = To.at(i); i++;
                        if(stop.at(to) || to == back) continue;
                        C1.at(to) = cpos1,C2.at(to) = cpos2;
                        st.push({to,start.at(to),pos}); break;
                    }
                }
            };
            for(int i=start.at(p); i<start.at(p+1); i++){
                int to = To.at(i);
                if(stop.at(to) == false) dfs(to,p),cpos2++;
            }    
            C1.at(p) = cpos1++;
        }
        
        auto[B1,G1] = AuxiliaryTree(C1,cpos1);
        auto[B2,G2] = AuxiliaryTree(C2,cpos2);
        
        int idx = 0;
        for(auto &G : G1){
            int root = -1;
            while(root == -1) root = Ps.at(idx++);
            idx--;
            {
                auto dfs = [&](int s) -> void {
                    stack<tuple<int,int,int>> st;
                    st.push({s,start.at(s),-1});
                    V[s] = {1,0,dist2[s],0};
     
                    int dep = 0;
                    while(st.size()){
                        auto &[pos,i,back] = st.top();
                        while(true){
                            if(i == start.at(pos+1)){dep--,st.pop(); break;}
                            int to = To.at(i); i++;
                            if(stop.at(to) || to == back) continue;
                            dep++; V[to] = {1,dep,dist2[to],dep*dist2[to]};
                            st.push({to,start.at(to),pos}); break;
                        }
                    }
                };  
                dfs(root);
            }
            {
                auto dfs = [&](auto dfs,int pos,int back) -> tuple<ull,ull,ull,ull> {
                    int p = B1.at(idx).at(pos);
                    auto [c,d,e,s] = V[p]; V[p] = {0,0,0,0};
                    ull di = dist2[p]*2;
                    for(auto to : G.at(pos)){
                        if(to == back) continue;
                        auto [c2,d2,e2,s2] = dfs(dfs,to,pos);
                        if(c2 == 0) continue;
                        answer -= di*(d*c2+d2*c);
                        answer += d*e2+e*d2;
                        answer += s*c2+s2*c;
                        c += c2,d += d2,e += e2,s += s2;
                    }
                    return {c,d,e,s};
                };
                dfs(dfs,0,-1);
            }
            idx++;
        }
        cpos2 = 0;
        for(auto p : Ps) if(p != -1) for(int i=start.at(p); i<start.at(p+1); i++){
            int root = To.at(i);
            if(stop.at(root)) continue;
            auto &G = G2.at(cpos2);
            auto &B = B2.at(cpos2);
            {
                auto dfs = [&](int s,int b) -> void {
                    stack<tuple<int,int,int>> st;
                    st.push({s,start.at(s),b});
                    V[s] = {1,1,dist2[s],dist2[s]};
                    int dep = 1;
                    while(st.size()){
                        auto &[pos,i,back] = st.top();
                        while(true){
                            if(i == start.at(pos+1)){dep--,st.pop(); break;}
                            int to = To.at(i); i++;
                            if(stop.at(to) || to == back) continue;
                            dep++; V[to] = {1,dep,dist2[to],dep*dist2[to]};
                            st.push({to,start.at(to),pos}); break;
                        }
                    }
                };  
                dfs(root,p);
            }
            {
                auto dfs = [&](auto dfs,int pos,int back) -> tuple<ull,ull,ull,ull> {
                    int p = B.at(pos);
                    auto [c,d,e,s] = V[p]; V[p] = {0,0,0,0};
                    ull di = dist2[p]*2;
                    for(auto to : G.at(pos)){
                        if(to == back) continue;
                        auto [c2,d2,e2,s2] = dfs(dfs,to,pos);
                        answer += di*(d*c2+d2*c);
                        answer -= d*e2+e*d2;
                        answer -= s*c2+s2*c;
                        c += c2,d += d2,e += e2,s += s2;
                    }
                    return {c,d,e,s};
                };
                dfs(dfs,0,-1);
            }
            cpos2++;
        }

        vector<int> next;
        for(auto &p : Ps){
            if(p == -1) continue; 
            for(int i=start.at(p); i<start.at(p+1); i++){
                int to = To.at(i);
                if(!stop.at(to)) next.emplace_back(to);
            }
            stop.at(p) = true;
        }
        swap(Ps,next);
    }
    answer *= 2;
    //answer = 77714187941852070; //さいあく
    cout << answer << endl;
}
0