library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub tko919/library

:heavy_check_mark: Verify/LC_frequency_table_of_tree_distance.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/frequency_table_of_tree_distance"

#include "Template/template.hpp"

#include "Convolution/fft.hpp"

#include "Graph/centroid.hpp"


int main(){
    int n;
    cin>>n;
    CentroidDecomposition cd(n);
    rep(i,0,n-1){
        int x,y;
        cin>>x>>y;
        cd.add_edge(x,y);
    }
    vector<ll> ret(n);

    auto rec=[&](auto& _rec,int rt)->void{
        int cen=cd.find(rt);
        for(auto& to:cd.g[cen])if(!cd.used[to])_rec(_rec,to);
        vector<ll> sum,cur;
        auto dfs=[&](auto& f,int v,int p,int d)->void{
            if((int)cur.size()<=d)cur.resize(d+1);
            cur[d]++;
            for(auto& to:cd.g[v])if(to!=p and !cd.used[to])f(f,to,v,d+1);
        };
        for(auto& to:cd.g[cen])if(!cd.used[to]){
            cur.clear();
            dfs(dfs,to,cen,1);
            auto sub=FFT::square(cur);
            rep(i,0,min((int)sub.size(),n))ret[i]-=sub[i];
            if(sum.size()<cur.size())sum.resize(cur.size());
            rep(i,0,cur.size())sum[i]+=cur[i];
        }
        rep(i,0,min((int)sum.size(),n))ret[i]+=sum[i]*2;
        auto add=FFT::square(sum);
        rep(i,0,min((int)add.size(),n))ret[i]+=add[i];
        cd.used[cen]=0;
    };
    rec(rec,0);
    rep(i,1,n){
        ret[i]>>=1;
        cout<<ret[i]<<'\n';
    }
    return 0;
}
#line 1 "Verify/LC_frequency_table_of_tree_distance.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/frequency_table_of_tree_distance"

#line 1 "Template/template.hpp"
#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b-1); i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T, template <class> class C>
ostream &operator<<(ostream &os, const C<T> &v) {
    os << "[";
    for (auto d : v)
        os << d << ", ";
    os << "]";
    return os;
}
#line 2 "Convolution/fft.hpp"

namespace FFT{
    struct C{
        double x,y;
        C(double _x=0,double _y=0):x(_x),y(_y){}
        C operator~()const{return C(x,-y);}
        C operator*(const C& c)const{return C(x*c.x-y*c.y,x*c.y+y*c.x);}
        C operator+(const C& c)const{return C(x+c.x,y+c.y);}
        C operator-(const C& c)const{return C(x-c.x,y-c.y);}
    };
    vector<vector<C>> w(1,vector<C>(1,1));
    void init(int lg){
        for(int d=1,m=1;d<=lg;d++,m<<=1)if(d>=(int)w.size()){
             w.emplace_back(m);
             const double th=M_PI/m;
             for(int i=0;i<m;i++)w[d][i]=(i&1?C(cos(th*i),sin(th*i)):w[d-1][i>>1]);
        }
    }
    void fft(vector<C>& f,bool inv){
        const int n=f.size(); const int lg=__lg(n);
        if(lg>=(int)w.size())init(lg);
        if(inv){
            for(int k=1;k<=lg;k++){
                const int d=1<<(k-1);
                for(int s=0;s<n;s+=2*d){
                    for(int i=s;i<s+d;i++){
                        C x=f[i],y=~w[k][i-s]*f[d+i];
                        f[i]=x+y; f[d+i]=x-y;
                    }
                }
            }
         }
         else{
             for(int k=lg;k;k--){
                 const int d=1<<(k-1);
                 for(int s=0;s<n;s+=2*d){
                     for(int i=s;i<s+d;i++){
                         C x=f[i],y=f[d+i];
                         f[i]=x+y; f[d+i]=w[k][i-s]*(x-y);
                     }
                 }
             }
         }
    }
    template<typename T>vector<T> mult(const vector<T>& a,const vector<T>& b){
        const int as=a.size(); const int bs=b.size(); 
        if(!as or !bs)return {};
        const int cs=as+bs-1; vector<T> c(cs);
        if(max(as,bs)<16){
            for(int i=0;i<as;i++)for(int j=0;j<bs;j++){
                c[i+j]+=(int)a[i]*b[j];
            }
            return c;
        }
        const int n=1<<__lg(2*cs-1); vector<C> f(n);
        for(int i=0;i<as;i++)f[i].x=a[i];
        for(int i=0;i<bs;i++)f[i].y=b[i];
        fft(f,0); static const C rad(0,-.25);
        for(int i=0;i<n;i++){
            int j=i?i^((1<<__lg(i))-1):0;
            if(i>j)continue;
            C x=f[i]+~f[j],y=f[i]-~f[j];
            f[i]=x*y*rad; f[j]=~f[i];
        }
        fft(f,1); for(int i=0;i<cs;i++)c[i]=round(f[i].x/n);
        return c;
    }
    template<typename T>vector<T> square(const vector<T>& a){
        const int as=a.size(); if(!as)return {};
        const int cs=as*2-1; vector<T> c(cs);
        if(as<16){
            for(int i=0;i<as;i++)for(int j=0;j<as;j++){
                c[i+j]+=(int)a[i]*a[j];
            }
            return c;
        }
        const int n=1<<__lg(cs*2-1); vector<C> f(n);
        for(int i=0;i<as;i++)f[i].x=a[i];
        fft(f,0); for(int i=0;i<n;i++)f[i]=f[i]*f[i];
        fft(f,1); for(int i=0;i<cs;i++)c[i]=round(f[i].x/n);
        return c;
    }
}

/**
 * @brief Fast Fourier Transform
 */
#line 2 "Graph/centroid.hpp"

class CentroidDecomposition{
    void get(int v,int p){
        sz[v]=1;
        for(auto& to:g[v])if(to!=p and !used[to]){
            get(to,v);
            sz[v]+=sz[to];
        }
    }
    int dfs(int v,int p,int rt){
        for(auto& to:g[v])if(to!=p and !used[to]){
            if(sz[to]>(sz[rt]>>1))return dfs(to,v,rt);
        }
        return v;
    }
public:
    int n;
    vector<vector<int>> g;
    vector<int> sz,used;
    CentroidDecomposition(int n_):n(n_),g(n),sz(n),used(n){}
    void add_edge(int u,int v){
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int find(int rt){
        get(rt,-1);
        int res=dfs(rt,-1,rt);
        used[res]=1;
        return res;
    }
};

/**
 * @brief Centroid Decomposition
 */
#line 6 "Verify/LC_frequency_table_of_tree_distance.test.cpp"

int main(){
    int n;
    cin>>n;
    CentroidDecomposition cd(n);
    rep(i,0,n-1){
        int x,y;
        cin>>x>>y;
        cd.add_edge(x,y);
    }
    vector<ll> ret(n);

    auto rec=[&](auto& _rec,int rt)->void{
        int cen=cd.find(rt);
        for(auto& to:cd.g[cen])if(!cd.used[to])_rec(_rec,to);
        vector<ll> sum,cur;
        auto dfs=[&](auto& f,int v,int p,int d)->void{
            if((int)cur.size()<=d)cur.resize(d+1);
            cur[d]++;
            for(auto& to:cd.g[v])if(to!=p and !cd.used[to])f(f,to,v,d+1);
        };
        for(auto& to:cd.g[cen])if(!cd.used[to]){
            cur.clear();
            dfs(dfs,to,cen,1);
            auto sub=FFT::square(cur);
            rep(i,0,min((int)sub.size(),n))ret[i]-=sub[i];
            if(sum.size()<cur.size())sum.resize(cur.size());
            rep(i,0,cur.size())sum[i]+=cur[i];
        }
        rep(i,0,min((int)sum.size(),n))ret[i]+=sum[i]*2;
        auto add=FFT::square(sum);
        rep(i,0,min((int)add.size(),n))ret[i]+=add[i];
        cd.used[cen]=0;
    };
    rec(rec,0);
    rep(i,1,n){
        ret[i]>>=1;
        cout<<ret[i]<<'\n';
    }
    return 0;
}
Back to top page