题意:给定一个树形图,节点10^5,有两种操作,一种是把某两点间路径(路径必定唯一)上所有点的权值增加一个固定值。

另一种也是相同操作,不同的是给边加权值。操作次数10^5。求操作过后,每个点和每条边的权值。

分析:此题时间卡得非常紧,最好用输入外挂,最好不要用RMQ来求解LCA。

此题是典型的在线LCA问题,先讲讲在线LCA要怎么做。

在线LCA有两种方法,第一种比较常见,即将其转化成RMQ问题。

 

先对树形图进行深度优先遍历,遍历过程记录路线中点的途经序列,每个非叶子节点会在序列中出现多次,从一个节点A的一个子节点回到A点再走另一个子节点的时候要再次加A加入序列。

记录序列的同时还要记录序列中每个点在树中对应的深度。以及在序列中第一次出现的位置(其实不一定非要第一个才行),主要用于根据点标号查找其在序列中对应的下标。

此时,LCA已经转化为RMQ,如果要求a,b的LCA,只需要找到a,b在遍历序列中分别对应的位置,并在深度序列中查找以这两点为端点的区间内的最小值即可。这个最小值在遍历序列中对应的点就是他们的LCA。

这种方法预处理O(NlogN),查询是O(1)。

模板如下:

//first call init_LCA(root).
//then call LCA(a, b) to quest the LCA of a and b.
//the graph can be both bidirected or unidirected.
#define MAX_NODE_NUM 0
#define MAX_EDGE_NUM 0
#define M 30

struct Edge
{
    int v, next, id;
    Edge()
    {}
    Edge(int v, int next, int id):v(v), next(next), id(id)
    {}
} edge[MAX_EDGE_NUM];

int head[MAX_NODE_NUM];
int edge_cnt;

void init_edge()
{
    memset(head, -1, sizeof(head));
    edge_cnt = 0;
}

void add_edge(int u, int v, int id)
{
    edge[edge_cnt] = Edge(v, head[u], id);
    head[u] = edge_cnt++;
}

bool vis[MAX_NODE_NUM];
int father[MAX_NODE_NUM];
int power[M];
int st[MAX_NODE_NUM * 2][M];
int ln[MAX_NODE_NUM * 2];
int seq_cnt;
int seq[2*MAX_NODE_NUM];
int depth[2*MAX_NODE_NUM];
int first_appearance[MAX_NODE_NUM];

//returns the index of the first minimum value in [x, y]
void init_RMQ(int f[], int n)
{
    int i, j;
    for (power[0] = 1, i = 1; i < 21; i++)
    {
        power[i] = 2 * power[i - 1];
    }
    for (i = 0; i < n; i++)
    {
        st[i][0] = i;
    }
    ln[0] = -1;
    for (int i = 1; i <= n; i++)
    {
        ln[i] = ln[i >> 1] + 1;
    }
    for (j = 1; j < ln[n]; j++)
    {
        for (i = 0; i < n; i++)
        {
            if (i + power[j - 1] - 1 >= n)
            {
                break;
            }
            //for maximum, change ">" to "<"
            //for the last, change "<" or ">" to "<=" or ">="
            if (f[st[i][j - 1]] > f[st[i + power[j - 1]][j - 1]])
            {
                st[i][j] = st[i + power[j - 1]][j - 1];
            }
            else
            {
                st[i][j] = st[i][j - 1];
            }
        }
    }
}

int query(int x, int y)
{
    if(x > y)
    {
        swap(x, y);
    }
    int k = ln[y - x + 1];
    //for maximum, change ">" to "<"
    //for the last, change "<" or ">" to "<=" or ">="
    if (depth[st[x][k]] > depth[st[y - power[k] + 1][k]])
        return st[y - power[k] + 1][k];
    return st[x][k];
}


void dfs(int u ,int current_depth)
{
    vis[u] = true;
    first_appearance[u] = seq_cnt;
    depth[seq_cnt] = current_depth;
    seq[seq_cnt++] = u;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v;
        if (vis[v])
        {
            continue;
        }
        father[v] = u;
        if (!vis[v])
        {
            dfs(v, current_depth + 1);
            depth[seq_cnt] = current_depth;
            seq[seq_cnt++] = u;
        }
    }
}

void init_LCA(int root)
{
    memset(vis, 0, sizeof(vis));
    father[root] = -1;
    seq_cnt = 0;
    dfs(root, 0);
    init_RMQ(depth, seq_cnt);
}

//O(1)
int LCA(int u ,int v)
{
    int x = first_appearance[u];
    int y = first_appearance[v];
    int res = query(x, y);
    return seq[res];
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-12
猜你喜欢
  • 2022-12-23
  • 2021-10-01
  • 2021-11-21
  • 2022-12-23
  • 2021-12-04
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案