BZOJ 4543/3522: [POI2014] Hotel long chain split tree Dp +

title

BZOJ 3522

LUOGU 3565

Enhanced: BZOJ 4543

Simplify the meaning of the questions:

Has a tree structure, the same length of each side of any two nodes can reach each other.

Option 3 points, equal twenty-two distance, how many kinds of programs?

\(n\leqslant 5000\)

Enhanced: \ (the n-\ leqslant 1E5 \)

analysis

Significantly tree \ (Dp \) , and will be apparent to any two points three points must coincide midpoint, the intermediate node can be enumerated.

State as follows:

  • \ (f1 [j] \) represented by \ (I \) subtree rooted at the node number of a selected depth depth \ (J \) of the program number of nodes.
  • \ (f2 [j] \) represented by \ (I \) subtree rooted at the node number depth of two selected depth \ (J \) number of nodes of the program.
  • \ (f3 [j] \) represented by \ (I \) subtree rooted at the node number depth of three selected depth \ (J \) number of nodes of the program.

State transition to the principle of multiplying with multiplication, then they can accumulate.


Enhanced Edition:

Enumeration midpoint of the way does not work, we need to put it another thought.

Think of ways \ (Dp \) at:

Set \ (f [i] [j ] \) represented by \ (I \) is the subtree rooted to \ (I \) distance \ (J \) of the number of points.

Set \ (g [i] [j ] \) represented by \ (I \) is the root of the subtree in which the number of points may subtree \ (I \) outside, and the \ (I \) the distance \ (j \) is the number of dots to meet the meaning of the title triples.

\ (Dp \) when: each addition \ (I \) of a child \ (K \) after the promoter, to update answer:
\ [ANS = ANS + \ SUM ^ of N_ {J = 0} F [I] [J ] * g [k] [j + 1] + {j = 0} g [i \ sum ^ n_] [j] * f [k] \]

再更新 \(f\)\(g\)
\[ g[i][j]=g[i][j]+f[i][j]∗f[k]\\ f[i][j]=f[i][j]+f[k]\\ g[i][j]=g[i][j]+f[k] \]

We must pay attention to the order.

However, such complexity is still \ (O (N ^ 2) \) the need to optimize the transfer.

Consider \ (I \) and \ (son [i] \) if \ (I \) only one son, then
\ [f [i] [j ] = f [i] [j-1], g [i] [j] = g [i] [j + 1] \]

Therefore, by moving the pointer \ (O (1) \) solution.

So we thought of a way to optimize: Each node can be extended up to inherit the son of answers by moving the pointer, the other son of violence calculations.

The complexity of the algorithm is:
\ [\ sum_ = {I}. 1 ^ n-DEP [I] - \ sum_ = {I}. 1 ^ NDEP [I] -1 = O (N) \]

Complexity is transferred up each son \ (DEP \) , since the depth of a node must be pointed to a long-chain son depth \ (1 + \) , it is possible to save \ (dep-1 \) transfer times.

code

The wording constant little, ah, Los Valley's first point \ (T \)

#include<bits/stdc++.h>

typedef long long ll;
const int maxn=5e3+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

ll ans;int g[maxn],d[maxn];
inline void dfs1(int x,int fa,int rt)
{
    ans+=g[rt];
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        dfs1(y,x,rt+1);
    }
}

inline void dfs2(int x,int fa,int rt)
{
    g[rt]+=d[rt];
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        dfs2(y,x,rt+1);
    }
}

inline void dfs3(int x,int fa,int rt)
{
    ++d[rt];
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        dfs3(y,x,rt+1);
    }
}


int main()
{
    int n;read(n);
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    for (int x=1; x<=n; ++x)
    {
        memset(d,0,sizeof(d));
        memset(g,0,sizeof(g));
        for (int i=head[x]; i; i=Next[i])
        {
            int y=ver[i];
            dfs1(y,x,1);
            dfs2(y,x,1);
            dfs3(y,x,1);
        }
    }
    write(ans,'\n');
    IO::flush();
    return 0;
}

Writing look better, with the multiplication principle to statistics, the constant smaller

#include<bits/stdc++.h>

typedef long long ll;
const int maxn=5e3+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

int dep[maxn],md,n;
ll g[maxn];
inline void dfs(int x,int fa)
{
    chkMax(md,dep[x]);
    ++g[dep[x]];
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        dep[y]=dep[x]+1;
        dfs(y,x);
    }
}

ll f1[maxn];//f1[j]表示以 i 号节点为根的子树中深度为选出一个深度为 j 的节点的方案数
ll f2[maxn];//f2[j]表示以 i 号节点为根的子树中深度为选出两个深度为 j 的节点的方案数
ll f3[maxn];//f3[j]表示以 i 号节点为根的子树中深度为选出三个深度为 j 的节点的方案数
inline ll query(int x)
{
    ll sum=0;
    memset(f1,0,sizeof(f1));
    memset(f2,0,sizeof(f2));
    memset(f3,0,sizeof(f3));
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        dep[y]=md=1;
        dfs(y,x);
        for (int j=md; j; --j) f3[j]+=f2[j]*g[j], f2[j]+=f1[j]*g[j], f1[j]+=g[j], g[j]=0;
    }
    for (int i=1; i<=n; ++i) sum+=f3[i];
    return sum;
}

int main()
{
    read(n); ll ans=0;
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    for (int i=1; i<=n; ++i) ans+=query(i);
    write(ans,'\n');
    IO::flush();
    return 0;
}

Enhanced version of the long-chain split coming

#include<bits/stdc++.h>

typedef long long ll;
const int maxn=1e5+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

int dep[maxn],son[maxn];
inline void dfs(int x,int fa)
{
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        dfs(y,x);
        if (dep[y]>dep[son[x]]) son[x]=y;
    }
    dep[x]=dep[son[x]]+1;
}

ll space[maxn*10],*now=space+maxn;
ll *f[maxn],*g[maxn], ans;
inline void create(int id)
{
    f[id]=now, now+=dep[id]<<1|1;
    g[id]=now, now+=dep[id]<<1|1;
}

inline void Dp(int x,int fa)
{
    f[x][0]=1;
    if (son[x])
    {
        f[son[x]]=f[x]+1;
        g[son[x]]=g[x]-1;
        Dp(son[x],x);
        ans+=g[son[x]][1];
    }
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa || y==son[x]) continue;
        create(y);
        Dp(y,x);
        for (int j=dep[y]; j>=0; --j)
        {
            if (j) ans+=f[x][j-1]*g[y][j];
            ans+=g[x][j+1]*f[y][j];
            g[x][j+1]+=f[x][j+1]*f[y][j];
        }
        for (int j=0; j<=dep[y]; ++j)
        {
            if (j) g[x][j-1]+=g[y][j];
            f[x][j+1]+=f[y][j];
        }
    }
}
int main()
{
    int n;read(n);
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    dfs(1,0);
    create(1);
    Dp(1,0);
    write(ans,'\n');
    IO::flush();
    return 0;
}

Guess you like

Origin www.cnblogs.com/G-hsm/p/11409578.html