09 encounter with graph theory: tree heuristic merge

Heuristic tree merger

A look at this example:

Given a length \ (10 ^ 5 \) sequence, the sequence is \ ([0,1000000] \) is an integer, then there is \ (10 ^ 5 \) views interrogation, interrogation were two kinds: Review a value of the position of the sequence, and the query interval \ ([L, R] \ ) a total of how many different numbers within.

Is not considered segment tree approach.We can think of to solve the problem in a team --- Mo Mo sorted according to the team's routine with a barrel can be maintained up to 1 million barrels, the complexity of the \ (O (N \ sqrt {N}) \) . You can see, our core idea is to change the sort order of access at each location, thereby reducing complexity.

Then we see the following examples (If the above is not to elicit dsu I will utter?):

Of a given size \ (10 ^ 6 \) trees, each tree is a point \ ([0,1000000] \) is an integer, then there is \ (10 ^ 5 \) times query, the query within a subtree a total of how many different numbers.

Tree Mo team? But now I need to \ (NlogN \) algorithm. So we refer to Mo team thinking, is it possible to reduce the complexity by modifying the access order? This algorithm is called "tree heuristic merge", generally written \ (the DSU \) .

Consider the practice of violence, deal with violence is the answer to all the sub-tree, then \ (O (1) \) answer. Recursively traverse the whole tree, then for each point \ (u \) , calculated violence \ (u \) answer subtree. Complexity \ (O (N ^ 2) \) .

We finished in the calculation of \ (u \) son (v \) \ After the answer, we need to calculate \ (v \) answer to \ (u \) contributions, then \ (v \) answers deleting . So we found the answer to the last one sub-tree is not required to remove. Comparison of us thinking we would surely large subtree put the final processing. Then we found another beautiful thing: a heavy chain split. Because of the heavy chain split practice, every time we go to his son after the light, reducing the size of the tree will be at least \ (\ FRAC. 1} {2} {\) , so that each node on the path to the root at most \ (\ log_2n \) strips light side, each point is obtained further edge-connected light up ancestor traversal \ (\ log_2n \) times. So we baryon tree into the final process, priority go light side, walking and violent answer process lepton tree, then route any heavy son to the root of all the heavy side connections ancestors computing finish their lepton tree before the answer is not there down to this point, so a number of points to be traversed is equal to \ (log_2n + 1 \) . Complexity is \ (NlogN \) .

To sum up, the basic flow of the algorithm is: \ (O (n-) \) a heavy chain split, \ (O (nlogn) \) tree heuristic combined, wherein each of the time points to traverse to a subtree of the processing light answers with information lepton tree to update their answers, and then delete the lepton tree information, traversing heavy son. Finally \ (O (m) \) answer.


Here's an example:

CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

A root of the tree 1, each side has a character (av of 22 species). A simple path is called Dokhtar-kosh if and only if the character on the path after reordered into a palindromic sequence. Seeking the longest tree length Dokhtar-kosh each sub-path.

\ (1 {\ leq} n {\ leq} 5 · 10 ^ 5 \)


Properties are obvious: the number appears on the path palindromic odd character at most one. Then we can shape the pressure, let \ (i \) represents the number of characters appear odd state on the path, then at most only 22 cases, the enumeration can be.

Since the required length of the longest path, we set \ (u \) is \ (v \) of ancestors, and u parity status path to the root of v the same, then the \ (v \) clearly superior \ (u \ ) , because \ (v \) greater depth. So we set up an array \ (cnt_i \) indicates the path for the state \ (i \) maximum depth.

How to get the status of a path? End points set path is \ (U, V \) , then the state is \ (state_u \) ^ \ (state_v \) ^ \ (STATE_ {LCA} \) ^ {STATE_ {LCA}}, where \ (state_x \ ) represents \ (X \) parity path to the root state.

, An algorithm is: first \ (O (n) \) a heavy chain split, and the process \ (State \) array; and \ (DSU \) . Time complexity is \ (O (nlogn) \) .

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 500010
using namespace std;

int dep[maxn],son[maxn],size[maxn],ldfn[maxn],rdfn[maxn],id[maxn],dfn;
int col[maxn],cnt[(1<<22)-1],state[maxn],ans[maxn];
int n,nowson;

struct edge{
    int to,col,next;
}e[maxn<<1];
int head[maxn],k;

inline void add(const int &u,const int &v,const int &w){
    e[k]=(edge){v,w,head[u]},head[u]=k++;
}

void dfs_getson(int u,int fa){
    size[u]=1,ldfn[u]=++dfn,id[dfn]=u;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa) continue;
        dep[v]=dep[u]+1,state[v]=state[u]^e[i].col,dfs_getson(v,u),size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
    rdfn[u]=dfn;
}

void dsu(int u,int fa,bool op){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa||v==son[u]) continue;
        dsu(v,u,false),ans[u]=max(ans[u],ans[v]);
    }
    if(son[u]) dsu(son[u],u,true),ans[u]=max(ans[u],ans[son[u]]);
    if(cnt[state[u]]) ans[u]=max(ans[u],cnt[state[u]]-dep[u]);
    for(register int i=0;i<22;++i) if(cnt[state[u]^(1<<i)])
        ans[u]=max(ans[u],cnt[state[u]^(1<<i)]-dep[u]);
    cnt[state[u]]=max(cnt[state[u]],dep[u]);
    for(register int i=head[u];~i;i=e[i].next){
        register int v=e[i].to;
        if(v==fa||v==son[u]) continue;
        for(register int j=ldfn[v];j<=rdfn[v];++j){
            register int w=id[j];
            if(cnt[state[w]]) ans[u]=max(ans[u],cnt[state[w]]+dep[w]-2*dep[u]);
            for(register int k=0;k<22;++k) if(cnt[state[w]^(1<<k)])
                ans[u]=max(ans[u],cnt[state[w]^(1<<k)]+dep[w]-2*dep[u]);
        }
        for(register int j=ldfn[v];j<=rdfn[v];++j) cnt[state[id[j]]]=max(cnt[state[id[j]]],dep[id[j]]);
    }
    if(!op) for(register int i=ldfn[u];i<=rdfn[u];++i) cnt[state[id[i]]]=0;
}

int main(){
    memset(head,-1,sizeof head);
    cin>>n;
    for(register int i=2;i<=n;++i){
        int to; char col;
        cin>>to>>col;
        add(to,i,1<<(col-'a')),add(i,to,1<<(col-'a'));
    }
    dep[1]=1,dfs_getson(1,-1),dsu(1,-1,true);
    for(register int i=1;i<=n;++i) printf("%d ",ans[i]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/akura/p/11531192.html