codeforces 102862H

H. Optimize DFS
time limit per test3 seconds
memory limit per test256 megabytes
You are given a tree with 𝑛 vertices. Every vertex 𝑣 has two values 𝑎𝑣 and 𝑏𝑣. You have to process 𝑞 queries of types:

Given 𝑣 and 𝑥, assign 𝑎𝑣=𝑥;
Given 𝑣, print 𝑎𝑣;
Given 𝑣, implement the following procedure efficiently:
First, create an array used[1…𝑛] filled with false initially. Then run the function DFS(𝑣):

DFS(v):
{
    used[v] = true;
    for u from 1 to n do
    {
        if (u and v are connected by an edge)
           and (used[u] == false)
           and (a[v] + b[u] == a[u] + b[v]) then
        {
            DFS(u);
        }
    }
    a[v] = b[v];
}

Note that the array used is independent for each query of the 3rd type.
Input
The first line contains two integers 1≤𝑛,𝑞≤5⋅105. The second line contains 𝑛 integers, where the 𝑖-th is the initial value of 𝑎𝑖 (0≤𝑎𝑖≤5⋅105). The third line contains 𝑛 integers, where the 𝑖-th is the value of 𝑏𝑖 (0≤𝑏𝑖≤5⋅105).

Each of the next 𝑛−1 lines describes an edge of the tree. The 𝑖-th line contains two integers 𝑢𝑖 and 𝑣𝑖 (1≤𝑢𝑖,𝑣𝑖≤𝑛, 𝑢𝑖≠𝑣𝑖), the indices of the vertices connected by the 𝑖-th edge. It is guaranteed that the given graph is a tree.

The next 𝑞 lines contain the description of the queries. The 𝑖-th query starts with an integer 𝑡𝑖 (1≤𝑡𝑖≤3) that denotes the type of the query. If 𝑡𝑖=1, then two integers 𝑣𝑖 and 𝑥𝑖 follow (1≤𝑣𝑖≤𝑛, 0≤𝑥𝑖≤5⋅105). Otherwise only 𝑣𝑖 is given.

Output
For each query of the 2nd type output one integer, the value 𝑎𝑣.

题目要求我们按照树的构造进行多次操作,
三次操作分别是1.替换a[v]=x;
2.查询a[x]当前值
3.进行特殊的dfs,交换特定的值

其中包含了特殊的dfs
关键代码如下

点击查看代码
void dfs(int v){
    used[v] = 1;
    for (Edge* e = graph[v]; e != NULL; e = e->next){
        int u = e->to;
        if(!used[u] && a[v] + b[u] == a[u] + b[v]){
            dfs(u);
        }
    }
    a[v] = b[v];
}

完整代码如下

点击查看代码
#include <stdio.h>
#include <stdlib.h>

#define MAXN 100005

typedef struct Edge{
    int to;
    struct Edge* next;
} Edge;


Edge* graph[MAXN];  // 每个节点的邻接链表头指针
int used[MAXN];
int a[MAXN], b[MAXN];
//头插法建树
void add_edge(int u, int v){
    Edge* e = (Edge*)malloc(sizeof(Edge));
    e->to = v;
    e->next = graph[u];
    graph[u] = e;
}

void dfs(int v){
    used[v] = 1;
    for (Edge* e = graph[v]; e != NULL; e = e->next){
        int u = e->to;
        if(!used[u] && a[v] + b[u] == a[u] + b[v]){
            dfs(u);
        }
    }
    a[v] = b[v];
}

int main(){
    int n,p;
    scanf("%d%d",&n, &p);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= n; i++){
        scanf("%d", &b[i]);
    }
    //建树
    for (int i = 1; i < n; i++){
        int u, v;
        scanf("%d %d", &u, &v);
        add_edge(u, v);
        add_edge(v, u);
    }
    while(p--){
        int q;
        scanf("%d",&q);
        if(q == 1){
            int v,x;
            scanf("%d%d",&v, &x);
            a[v] = x;
        }else if(q == 2){
            int v;
            scanf("%d",&v);
            printf("%d\n",a[v]);
        }else if(q == 3){
            int v;
            scanf("%d", &v);
            // 一开始树的元素都没有被访问
            for (int i = 1; i <= n; i++) {
                used[i] = 0;
            }
            dfs(v);
        }
    }
    return 0;
}

操作时每次的v记得初始化 还有就是时间复杂度和时间要求可以注意下
posted @ 2025-06-05 00:34  sirro1uta  阅读(14)  评论(0)    收藏  举报