• 线段树合并


    Recently, TeaTree acquire new knoledge gcd (Greatest Common Divisor), now she want to test you.
    As we know, TeaTree is a tree and her root is node 1, she have n nodes and n-1 edge, for each node i, it has it’s value v[i].
    For every two nodes i and j (i is not equal to j), they will tell their Lowest Common Ancestors (LCA) a number : gcd(v[i],v[j]).
    For each node, you have to calculate the max number that it heard. some definition:
    In graph theory and computer science, the lowest common ancestor (LCA) of two nodes u and v in a tree is the lowest (deepest) node that has both u and v as descendants, where we define each node to be a descendant of itself.

    InputOn the first line, there is a positive integer n, which describe the number of nodes.
    Next line there are n-1 positive integers f[2] ,f[3], …, f[n], f[i] describe the father of node i on tree.
    Next line there are n positive integers v[2] ,v[3], …, v[n], v[i] describe the value of node i.
    n<=100000, f[i]<i, v[i]<=100000OutputYour output should include n lines, for i-th line, output the max number that node i heard.
    For the nodes who heard nothing, output -1.Sample Input
    4
    1 1 3
    4 1 6 9
    Sample Output
    2
    -1
    3
    -1

    题意 : 给你一颗树,求以任意一个点为根节点时,该子树内最大的 gcd 是多少,并且所求gcd的两个点的 lca 等于根节点
    思路分析 : 1 . 用 vector 模拟归并排序,预处理一下每个数字的约数有哪些,然后合并就可以了
    #define ll long long
    const int maxn = 1e5+5;
    
    int n;
    vector<int>d[maxn], ve[maxn], f[maxn];
    void init(){
        for(int i = 1; i <= 100000; i++){
            for(int j = i; j <= 100000; j += i){
                d[j].push_back(i);
            }
        } 
    }
    int val[maxn], ans[maxn];
    vector<int>temp;
    
    void merge(int x, int y){
        temp.clear();    
        if (f[x].size() == 0) f[x] = d[val[x]];
        if (f[y].size() == 0) f[y] = d[val[y]];
        
        int i = 0, j = 0;
        while((i < f[x].size()) && (j < f[y].size())){
            if (f[x][i] < f[y][j]) temp.push_back(f[x][i]), i++;
            else if (f[x][i] > f[y][j]) temp.push_back(f[y][j]), j++;
            else {
                temp.push_back(f[x][i]);
                ans[x] = max(ans[x], f[x][i]); i++, j++;
            }
        }
        while (i < f[x].size()) {
            temp.push_back(f[x][i]);
            i++;
        }
        while(j < f[y].size()) {
            temp.push_back(f[y][j]);
            j++;
        }
        f[x].clear(); f[y].clear();
        f[x] = temp; 
    }
    
    
    void merge8(int x,int v)
    {
        int i = 0, j = 0;
        vector<int>tem;
        for(; i < f[x].size() && j < f[v].size();)
        {
            int a1 = f[x][i], a2 = f[v][j];
            if(a1 < a2)
            {
                tem.push_back(a1);
                i++;
            }
            else if(a1 == a2)
            {
                ans[x] = max(ans[x],a1);
                tem.push_back(a1); 
                i++;j++; 
            }
            else
            {
                tem.push_back(a2); 
                j++;
            }
        }
        for(; i < f[x].size(); i++)tem.push_back(f[x][i]);
        for(; j < f[v].size(); j++)tem.push_back(f[v][j]);
        f[x] = tem;
        return;
    }
    
    void dfs(int x){
        for(int i = 0; i < ve[x].size(); i++){
            int to = ve[x][i];
            dfs(to);
            merge(x, to);
        }
    }
    
    int main() {
        init();
        cin >> n;
        
        int x;
        memset(ans, -1, sizeof(ans));
        for(int i = 2; i <= n; i++){
            scanf("%d", &x);
            ve[x].push_back(i);
        }
        for(int i = 1; i <= n; i++){
            scanf("%d", &val[i]);
            //f[i] = d[val[i]]; 
        }
        dfs(1);    
        for(int i = 1; i <= n; i++) printf("%d
    ", ans[i]);
        return 0;
    }
    

     2 . 对每个权值建立一颗权值线段树,10万以内的数不同的约数最多有 400  个,然后将线段树两两合并即可

    代码示例 :

    #define ll long long
    const int maxn = 1e5+5;
    
    int n;
    vector<int>ve[maxn], d[maxn];
    int root[maxn], cnt = 1;
    int lson[maxn*400], rson[maxn*400], maxx[maxn*400];
    
    void init(){
        for(int i = 1; i <= 100000; i++){
            for(int j = i; j <= 100000; j += i) 
                d[j].push_back(i);
        } 
    }
    
    void pushup(int k){
        if (lson[k] && rson[k]) maxx[k] = max(maxx[lson[k]], maxx[rson[k]]);
        else if (lson[k]) maxx[k] = maxx[lson[k]];
        else if (rson[k]) maxx[k] = maxx[rson[k]];
    }
    
    void update(int &rt, int l, int r, int num){
        if (!rt) rt = cnt++;
        if (l == r) { maxx[rt] = num; return; }
        int mid = (l+r)>>1;
        
        if (num <= mid) update(lson[rt], l, mid, num);
        else update(rson[rt], mid+1, r, num);
        pushup(rt);
    }
    
    int merge(int x, int y, int &ans){ 
        if (!x || !y) return x^y;
        
        if (maxx[x] == maxx[y]) ans = max(ans, maxx[x]);
        if (lson[x] || lson[y]) lson[x] = merge(lson[x], lson[y], ans);
        if (rson[x] || rson[y]) rson[x] = merge(rson[x], rson[y], ans);
        
        pushup(x);
        return x;
    }
    
    int ans[maxn];
    void dfs(int x){
        ans[x] = -1;
        
        for(int i = 0; i < ve[x].size(); i++){
            int to = ve[x][i];
            dfs(to);
            root[x] = merge(root[x], root[to], ans[x]);
        }
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
        int x;
        init();
        
        cin >> n;
        for(int i = 2; i <= n; i++){
            scanf("%d", &x);
            ve[x].push_back(i);
        } 
        int val;
        for(int i = 1; i <= n; i++){
            root[i] = 0;
            scanf("%d", &val);
            for(int j = 0; j < d[val].size(); j++){
                update(root[i], 1, 100000, d[val][j]);
            }        
        }
        dfs(1);
        for(int i = 1; i <= n; i++) printf("%d
    ", ans[i]);
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    web.xml+spring mvc基本配置
    REST服务安全-双向认证
    thymeleaf 配置
    jenkins
    linux下ssh/scp无密钥登陆方法
    java编译 Error: Could not find or load main class java执行包main方法
    文本按列导入excel
    linux脚本-判断进程是否存在,从而可以做预警处理..
    Linux中顿号
    >/dev/null 2>&1
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/9733752.html
Copyright © 2020-2023  润新知