zoukankan      html  css  js  c++  java
  • Aizu:2170-Marked Ancestor

    Marked Ancestor

    Time limit 8000 ms
    Memory limit 131072 kB

    Problem Description

    You are given a tree T that consists of N nodes. Each node is numbered from 1 to N, and node 1 is always the root node of T. Consider the following two operations on T:

    M v: (Mark) Mark node v.
    Q v: (Query) Print the index of the nearest marked ancestor of node v which is nearest to it. Initially, only the root node is marked.
    

    Your job is to write a program that performs a sequence of these operations on a given tree and calculates the value that each Q operation will print. To avoid too large output file, your program is requested to print the sum of the outputs of all query operations. Note that the judges confirmed that it is possible to calculate every output of query operations in a given sequence.

    Input

    The input consists of multiple datasets. Each dataset has the following format:

    The first line of the input contains two integers N and Q, which denotes the number of nodes in the tree T and the number of operations, respectively. These numbers meet the following conditions: 1 ≤ N ≤ 100000 and 1 ≤ Q ≤ 100000.

    The following N - 1 lines describe the configuration of the tree T. Each line contains a single integer pi (i = 2, … , N), which represents the index of the parent of i-th node.

    The next Q lines contain operations in order. Each operation is formatted as “M v” or “Q v”, where v is the index of a node.

    The last dataset is followed by a line containing two zeros. This line is not a part of any dataset and should not be processed.

    Output

    For each dataset, print the sum of the outputs of all query operations in one line.

    Sample Input

    6 3
    1
    1
    2
    3
    3
    Q 5
    M 3
    Q 5
    0 0

    Output for the Sample Input

    4


    解题心得:

    1. 题意就是有一棵树,有两种操作,第一种是将某个点标记,第二种是询问距离某个点被标记的最进的祖先节点的编号,最后需要你打印出所有询问编号的总和。
    2. 据说这题每次回溯跑暴力都能跑出来,因为时间给了八秒嘛,其实我感觉这是考了一个并查集关于树的变形
      这里写图片描述这样改变了树的深度,在询问答案的时候就可以O(1)得到答案,那怎么改变树的的形态呢。
    3. 其实可以将树的每个结点看成一颗新的树,每次标记的时候就可以将这个标记的节点看成根节点,形成一个子树,然后将它下面没有出现子树的部分全部合并起来。

    #include <algorithm>
    #include <stdio.h>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn = 1e5+100;
    
    int father[maxn],n,m;
    bool vis[maxn];
    vector <int> ve[maxn];
    
    void init() {
        for(int i=1;i<=n;i++) {
            ve[i].clear();
            father[i] = 1;
            vis[i] = false;
        }
        for(int i=2;i<=n;i++) {
            int temp;
            scanf("%d",&temp);
            ve[temp].push_back(i);
        }
        vis[1] = true;
    }
    
    void dfs(int x,int fa) {
        if(vis[x])
            return ;
        father[x] = fa;
        for(int i=0;i<ve[x].size();i++) {
            dfs(ve[x][i],fa);
        }
    }
    
    void Mark(int x) {
        vis[x] = true;
        father[x] = x;
        for(int i=0;i<ve[x].size();i++)
            dfs(ve[x][i],x);
    }
    
    void Solve() {
        long long sum = 0;
        for(int i=0;i<m;i++) {
            char temp[5];
            int x;
            scanf("%s%d",temp,&x);
            if(temp[0] == 'M')
                Mark(x);
            else
                sum += father[x];
        }
        printf("%lld
    ",sum);
    }
    
    int main() {
        while(scanf("%d%d",&n,&m) && n|m) {
            init();
            Solve();
        }
        return 0;
    }
  • 相关阅读:
    进程,进程
    hmac和socketserver
    下载Eclipse、下载Java各个版本,来这里就对了
    Java循环语句怎么用?经典排序算法见真知
    CSS基本语法
    Html属性标签
    HTML标记大全参考手册
    composer 安装Laravel (win10)
    composer 安装(win)
    GIT
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107137.html
Copyright © 2011-2022 走看看