Long chain split Summary

Split is a similar long chain \ (\ rm {dsu \ on \ tree} \) an algorithm, written like a normal tree chain split (split heavy chain), except that \ (\ rm {siz } \) maximum changed to \ (\ rm {dep} \ ) the maximum can optimize some time associated with the sub-tree depth problems.

nature

1, all of the chain lengths and \ (O (n) \) level

All points are only in a long chain where it will only be counted once, so is \ (O (n) \) level

2, where the long-chain length not less than the father its son's long chain

If the above does not hold, then the father of the son of points can be selected such that the long chain longer, in contradiction with the original.

This property has a corollary: For any point, it \ (k \) long chain where the ancestors of times greater than or equal inevitably \ (k \) , proved similar.

3, jumping from a starting point up, the switching frequency is a long-chain \ (O (\ sqrt n) \) level

The nature of the \ (2 \) , each transition will not be long chain lengths less than the last, i.e., the worst case jump rope long chain length \ (l, 2,3, \ cdots \) , i.e. jump \ (O (\ sqrt n) \) times

Implementation and examples

Achieve a long-chain split in a first heavy chain dfs similar split.

void dfs1(int u,int fu)
{
    for (int i=head[u];i;i=sq[i].nxt)
    {
        int v=sq[i].to;
        if (v==fu) continue;
        dfs1(v,u);
        if (len[son[u]]<len[v]) son[u]=v;
    }
    len[u]=len[son[u]]+1;
}

Wherein \ (len \) recorded is \ (U \) long chain where \ (U \) subtree length.

1, seeking \ (k \) level ancestor

The general idea is that the multiplication can be done \ (O (n \ log n ) \) pretreatment \ (O (\ log n) \) inquiry, looks very good, but you can do better.

Consider the long chain split, and for the length of each long chain \ (m \) , at which the pretreatment chain top up \ (K \) ancestor and downward \ (K \) heavy son , which is known by the nature of the 1 \ (O (n) \) after we jump to this point for each challenge \ (x \) on level ancestor to ensure that the chain length of a long chain of ancestors where \ (> KX \) , then jump to after top strand of this chain, the answer is determined according to a result of the pretreatment.

How to ensure the chain length \ (> kx \) it? Each discovery \ (K \) , note its binary representation of the highest bit \ (h_k \) bits, then let \ (x = 2 ^ {h_k } \) can, so the pre-treatment and the same doubling that array to the total is \ (O (n \ log n ) \) pretreated \ (O (1) \) query.

Example: luogu5903

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
struct node{int to,nxt;}sq[1001000];
int all=0,head[500500];
int n,dep[500500],mx[500500],son[500500],fa[500500][20],tp[500500],rt,hbit[500500],q;
vector<int> U[500500],D[500500];

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

#define ui unsigned int
ui s;

inline ui get(ui x) {
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return s = x; 
}

void add(int u,int v)
{
    all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
}

void dfs1(int u,int fu)
{
    dep[u]=dep[fu]+1;mx[u]=dep[u];fa[u][0]=fu;
    rep(i,1,19) fa[u][i]=fa[fa[u][i-1]][i-1];
    go(u,i)
    {
        int v=sq[i].to;
        if (v==fu) continue;
        dfs1(v,u);
        if (mx[v]>mx[u]) {son[u]=v;mx[u]=mx[v];}
    }
}

void dfs2(int u,int tpu)
{
    tp[u]=tpu;
    if (u==tpu)
    {
        int now=u;
        rep(i,0,mx[u]-dep[u])
        {
            D[u].pb(now);
            now=son[now];
        }
        now=u;
        rep(i,0,mx[u]-dep[u])
        {
            U[u].pb(now);
            now=fa[now][0];
        }
    }
    if (son[u]) dfs2(son[u],tpu);
    go(u,i)
    {
        int v=sq[i].to;
        if ((v==fa[u][0]) || (v==son[u])) continue;
        dfs2(v,v);
    }
}

int query(int x,int k)
{
    if (!k) return x;
    x=fa[x][hbit[k]];k-=(1<<hbit[k]);
    //cout << "half " << x << " " << k << endl;
    k-=(dep[x]-dep[tp[x]]);x=tp[x];
    //cout << "now " << x << " " << k << endl;
    if (k>=0) return U[x][k];else return D[x][-k];
}

int main()
{
    n=read();q=read();s=read();
    rep(i,1,n)
    {
        int fa=read();
        add(fa,i);add(i,fa);
        if (!fa) rt=i;
    }
    rep(i,2,n) hbit[i]=hbit[i>>1]+1;
    dfs1(rt,0);dfs2(rt,rt);
    int ans=0;ll fin=0;
    rep(i,1,q)
    {
        int x=(get(s)^ans)%n+1,k=(get(s)^ans)%dep[x];
        ans=query(x,k);
        fin^=(1ll*i*ans);
    }
    printf("%lld",fin);
    return 0;
}

2, optimize certain dp

Some state of the form dp \ (F_ {U, I} \) , where \ (I \) This dimension only and depth. For such dp we can optimize the use of long-chain split. Specifically, we do first \ (u \) re-son after the son and the combined light of all of the answers to the above this go. If we can do when the merger \ (O (len) \) merger, the total time complexity is \ (O (\ SUM len) \) , which is \ (O (n) \)

Example: codeforces 1009F

Violence first write equation dp up: \ (F_ {U, I} \) represents the \ (U \) distance subtree \ (U \) is equal to \ (I \) the number of points, then Have

\[ f_{u,0}=1,f_{u,i}=\sum_{v\in son_u} f_{v,i-1} \]

Only the information of the second dimension and depth of, can then be used to optimize the long-chain split dp


#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
struct node{int to,nxt;}sq[2002000];
int all=0,head[1001000];
int n,son[1001000],ans[1001000],*f[1001000],tmp[1001000],*id=tmp,len[1001000];

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void add(int u,int v)
{
    all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
}

void dfs1(int u,int fu)
{
    go(u,i)
    {
        int v=sq[i].to;
        if (v==fu) continue;
        dfs1(v,u);
        if (len[son[u]]<len[v]) son[u]=v;
    }
    len[u]=len[son[u]]+1;
}

void dfs2(int u,int fu)
{
    f[u][0]=1;
    if (son[u])
    {
        f[son[u]]=f[u]+1;
        dfs2(son[u],u);
        ans[u]=ans[son[u]]+1;
    }
    go(u,i)
    {
        int v=sq[i].to;
        if ((v==fu) || (v==son[u])) continue;
        f[v]=id;id+=len[v];dfs2(v,u);
        rep(j,1,len[v])
        {
            f[u][j]+=f[v][j-1];
            if (((j<ans[u]) && (f[u][j]>=f[u][ans[u]])) || ((j>ans[u]) && (f[u][j]>f[u][ans[u]])))
                ans[u]=j;
        }
    }
    if (f[u][ans[u]]==1) ans[u]=0;
}

int main()
{
    n=read();
    rep(i,1,n-1)
    {
        int u=read(),v=read();
        add(u,v);add(v,u);
    }
    dfs1(1,0);
    f[1]=id;id+=len[1];
    dfs2(1,0);
    rep(i,1,n) printf("%d\n",ans[i]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/encodetalker/p/12329372.html