zoukankan      html  css  js  c++  java
  • 总结:树上启发式合并

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

    算法的流程大概是这样: 
    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
    ",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 ? '
    ' : ' ');
        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
    ",ans[i] ? "Yes" : "No");
        }
    }
  • 相关阅读:
    大厂前端带来css3动画transition的使用和介绍全新认识动画
    js事件冒泡和事件捕获详解
    css3动画讲解,关于css3的@keyframes和animation
    [bug] Hive:java.net.ConnectException: Connection refused
    [bug] Hive:User root is not allowed to impersonate anonymous
    [bug] Hive:Permission denied: user=anonymous, access=EXECUTE, inode=”/tmp”
    [bug] Hive:Error: FUNCTION 'NUCLEUS_ASCII' already exists. (state=X0Y68,code=30000)
    [Python] 环境
    [Java] Web
    [计算机科学] 编程语言
  • 原文地址:https://www.cnblogs.com/tiberius/p/9394642.html
Copyright © 2011-2022 走看看