总结:树上启发式合并

这种算法能够解决关于询问一棵树的子树的相关信息的问题。

算法的流程大概是这样: 
1、dfs将一棵树建好,将节点的size、dfs序、重儿子、该dfs序对应的节点这些信息处理好(其他的信息具体问题具体分析)。 
2、进入solve函数,先去解决非重儿子,然后将这些非重儿子的信息暴力清空。 
3、接下来解决重儿子,这次不清空。 
4、然后再将非重儿子的信息再暴力添加。 
5、将该节点的信息添加进容器。 
6、回答关于这个节点的问题。 
7、返回。 

当然对于存信息的sum不一定是普通的数组,可能是map,可能是树状数组这类既支持插入又支持删除的容器,有适合的数据结构,而不是用数据结构去套题。

复杂度:

对于某个叶子节点来说,我们最终是要把它对答案的贡献加到根节点中,从而回答根节点的询问。可以知道,所有的节点其实都在重链上,

叶子节点到根节点的最多经过logn条轻边,我在将这个节点合并到根的时候,也顺便将别的节点合并到根上了,每合并一次,复杂度最多O(n)。

总的复杂度应该是O(nlogn)。

例题:

Codeforces 1009F

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;

int deep[maxn],num[maxn],son[maxn],ans[maxn],n,mx;
map<int,int> mp;
vector<int> graph[maxn];

void init(){
    memset(son,-1,sizeof(son));
}
void add(int cur,int fa){
    mp[deep[cur]] += 1;
    if(mp[deep[cur]] > mp[mx] || (mp[deep[cur]] == mp[mx] && deep[cur] < mx)) mx = deep[cur];
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        add(v,cur);
    }
}
void dfs(int cur,int fa){
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa || son[cur] == v) continue;
        dfs(v,cur);
        mp.clear();
        mx = 0;
    }
    if(son[cur] != -1) dfs(son[cur],cur);
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa || son[cur] == v) continue;
        add(v,cur);
    }
    mp[deep[cur]] += 1;
    if(mp[deep[cur]] > mp[mx] || (mp[deep[cur]] == mp[mx] && deep[cur] < mx)) mx = deep[cur];
    ans[cur] = mx - deep[cur];
}
void dfs1(int cur,int fa,int d){
    deep[cur] = d;
    num[cur] = 1;
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        dfs1(v,cur,d + 1);
        num[cur] += num[v];
        if(son[cur] == -1 || num[son[cur]] < num[v])
            son[cur] = v;
    }
}

int main(){
    scanf("%d",&n);
    for(int i = 0;i < n - 1;++i){
        int from,to;
        scanf("%d%d",&from,&to);
        graph[from].push_back(to);
        graph[to].push_back(from);
    }
    init();
    dfs1(1,0,1);
    dfs(1,0);
    for(int i = 1;i <= n;++i) printf("%d\n",ans[i]);
    return 0;
}

 

Codeforces 600E

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;

LL color[maxn],ans[maxn];
map<LL,int> mp;
map<int,LL> mp2;
vector<int> graph[maxn];
int deep[maxn],num[maxn],son[maxn],mx;
//map<LL,int>::iterator iter;

void add(int cur,int fa){
    int keep = ++mp[color[cur]];
    if(keep > mx) mx = keep;
    mp2[keep] += color[cur];
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        add(v,cur);
    }
}
void dfs(int cur,int fa){
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == son[cur] || v == fa) continue;
        dfs(v,cur);
        mp.clear();
        mp2.clear();
        mx = 0;
    }
    if(son[cur] != -1) dfs(son[cur],cur);
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(son[cur] == v || v == fa) continue;
        add(v,cur);
    }
    int keep = ++mp[color[cur]];
    if(keep > mx) mx = keep;
    mp2[keep] += color[cur];
    ans[cur] = mp2[mx];
}
void dfs1(int cur,int fa,int d){
    deep[cur] = d;
    num[cur] = 1;
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        dfs1(v,cur,d + 1);
        num[cur] += num[v];
        if(son[cur] == -1 || num[v] > num[son[cur]])
            son[cur] = v;
    }
}

int main(){
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;++i) scanf("%lld",&color[i]);
    memset(son,-1,sizeof(son));
    int from,to;
    for(int i = 0;i < n - 1;++i){
        scanf("%d%d",&from,&to);
        graph[from].push_back(to);
        graph[to].push_back(from);
    }
    dfs1(1,0,1);
    dfs(1,0);
    for(int i = 1;i <= n;++i)
        printf("%lld%c",ans[i],i == n ? '\n' : ' ');
    return 0;
}

 

Codeforces 570D

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;

struct query{
    int id,h;
    query(int a = 0,int b = 0){
        id = a,h = b;
    }
};

int deep[maxn],son[maxn],num[maxn],color[maxn],n,m;
char str[maxn];
bool ans[maxn];
map<int,int> mp;
vector<int> graph[maxn];
vector<query> ask[maxn];

inline int cnt1(int x){
    int ret = 0;
    while(x){
        x = x & (x - 1);
        ++ret;
    }
    return ret;
}
void add(int cur,int fa){
    mp[deep[cur]] ^= (1<<color[cur]);
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        add(v,cur);
    }
}
void dfs(int cur,int fa){
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa || v == son[cur]) continue;
        dfs(v,cur);
        mp.clear();
    }
    if(son[cur] != -1) dfs(son[cur],cur);
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa || v == son[cur]) continue;
        add(v,cur);
    }
    mp[deep[cur]] ^= (1<<color[cur]);
    for(int i = 0;i < ask[cur].size();++i){
        query q = ask[cur][i];
        int id = q.id,h = q.h;
        int mask = mp[h];
        int cnt = cnt1(mask);
        ans[id] = (cnt <= 1);
    }
}
void dfs1(int cur,int fa,int d){
    num[cur] = 1;
    deep[cur] = d;
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        if(v == fa) continue;
        dfs1(v,cur,d + 1);
        num[cur] += num[v];
        if(son[cur] == -1 || num[son[cur]] < num[v])
            son[cur] = v;
    }
}

int main(){
    scanf("%d%d",&n,&m);
    int fa;
    for(int i = 2;i <= n;++i){
        scanf("%d",&fa);
        graph[i].push_back(fa);
        graph[fa].push_back(i);
    }
    scanf("%s",str + 1);
    for(int i = 1;i <= n;++i) color[i] = str[i] - 'a';
    for(int i = 0;i < m;++i){
        int vi,hi;
        scanf("%d%d",&vi,&hi);
        ask[vi].push_back(query(i,hi));
    }
    memset(son,-1,sizeof(son));
    dfs1(1,0,1);
    dfs(1,0);
    for(int i = 0;i < m;++i){
        printf("%s\n",ans[i] ? "Yes" : "No");
    }
}

 

posted @ 2018-07-31 10:51  温和的提比略  阅读(106)  评论(0编辑  收藏  举报