zoukankan      html  css  js  c++  java
  • cf593d

    题意:给出一个有n(n<=200000)的树形图,每条边有一个权值。有两种操作,1是将一个边的权值变小,

    2是给定两点a,b和一个值y,用y(long long范围内)依次除以两点之间的路径上的所有边的权值,每次除法都是向下取整。

    并输出这个值。

    操作次数为m(m<=200000)。

    分析:

    这是一个较难的在线LCA问题。

    首先,每个y最多经过63次>=2的除数的除法就会变为0。

    建树并生成LCA。

    每次处理第2种请求时,我们都是先求两点的LCA,再分别处理两点到其LCA的路径。

    对于从低到高走路径的过程中,连续的权值为1的边,我们用一种类似于并查集的方式将他们缩成一条边。

    例如:a是b的父亲,边权值为1。那么我们领link[b]=a。否则我们令link[b]=b。

    这样如果出现连续的权值为1的边,我们不断追溯其link值直到与自身相等即可。记得使用并查集的路径压缩优化。

    那么我们处理单个路径时最多需要处理的边数约为63×2(权值>=2的和=1的边交替出现的情况)。

    所以总复杂度为O(mlogy)

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    #define d(x) 
    const int MAX_NODE_NUM  = (int)(2e5) + 100;
    const int M = 30;
    
    int n, m;
    vector<pair<int, long long> > edge[MAX_NODE_NUM];
    bool vis[MAX_NODE_NUM];
    int father[MAX_NODE_NUM][M];
    int depth[MAX_NODE_NUM];
    long long value[MAX_NODE_NUM];
    pair<int, int> p_edge[MAX_NODE_NUM];
    int link[MAX_NODE_NUM];
    
    void bfs(int root)
    {
        queue<int> q;
        q.push(root);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = true;
            for (int i = 0; i < (int)edge[u].size(); i++)
            {
                int v = edge[u][i].first;
                if (vis[v])
                {
                    continue;
                }
                father[v][0] = u;
                depth[v] = depth[u] + 1;
                value[v] = edge[u][i].second;
                link[v] = v;
                if (u != 0 && value[v] == 1)
                    link[v] = u;
                q.push(v);
            }
        }
    }
    
    //index start from 1.
    void init_LCA(int root)
    {
        fill_n(vis, n + 1, 0);
        memset(father, 0, sizeof(father));
        bfs(root);
        bool did;
        for (int i = 1; i < M; i++)
        {
            did = false;
            for (int j = 1; j <= n; j++)
            {
                int k = father[j][i - 1];
                if (k <= 0)
                {
                    continue;
                }
                father[j][i] = father[k][i - 1];
                did = true;
            }
            if (!did)
            {
                break;
            }
        }
    }
    
    //O(log(n))
    int LCA(int x, int y)
    {
        if (depth[x] > depth[y])
        {
            swap(x, y);
        }
        int diff = depth[y] - depth[x];
        for (int i = 0; i < M && diff; i++)
        {
            if (diff & 1)
            {
                y = father[y][i];
            }
            diff >>= 1;
        }
        if (x == y)
        {
            return x;
        }
        int exp = 0;
        while (x != y)
        {
            if (!exp || father[x][exp] != father[y][exp])
            {
                x = father[x][exp];
                y = father[y][exp];
                exp++;
            }else
            {
                exp--;
            }
        }
        return x;
    }
    
    long long next_ll()
    {
        long long a;
        scanf("%lld", &a);
        return a;
    }
    
    void input()
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n - 1; i++)
        {
            int a, b;
            long long c;
    
            scanf("%d%d", &a, &b);
            c = next_ll();
            edge[a].push_back(make_pair(b, c));
            edge[b].push_back(make_pair(a, c));
            p_edge[i] = make_pair(a, b);
        }
    }
    
    int get_link(int a)
    {
        if (a == link[a])
            return a;
        return link[a] = get_link(link[a]);
    }
    
    void make(int a, int lca, long long &w)
    {
        while (w > 0 && depth[a] > depth[lca])
        {
            w /= value[a];
            a = father[a][0];
            a = get_link(a);
        }
    }
    
    void work(int a, int b, long long w)
    {
        int lca = LCA(a, b);
        make(a, lca, w);
        make(b, lca, w);
        printf("%lld
    ", w);
    }
    
    void work(int p, long long w)
    {
        p--;
        int u = p_edge[p].first;
        int v = p_edge[p].second;
        if (depth[u] > depth[v])
        {
            swap(u, v);
        }
        value[v]= w;
        if (w == 1)
        {
            link[v] = link[u];
        }
    }
    
    int main()
    {
        input();
        init_LCA(1);
        for (int i = 0; i < m; i++)
        {
            int command;
            int a, b;
            long long c;
            scanf("%d", &command);
            if (command == 1)
            {
                scanf("%d%d", &a, &b);
                c = next_ll();
                work(a, b, c);
            }else
            {
                scanf("%d", &a);
                c = next_ll();
                work(a, c);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python pycurl属性
    HTTP报文-->MVC
    国际化信息-->MVC
    计算机网络入门概念理解
    TCP/IP基础概念及通信过程举例
    一道面试题:说说进程和线程的区别
    【转载】我眼中的Oracle性能优化
    【转载】数据库范式那些事
    【转载】详解CreateProcess调用内核创建进程的过程
    数据结构和算法(一):hash散列容器
  • 原文地址:https://www.cnblogs.com/rainydays/p/5079854.html
Copyright © 2011-2022 走看看