Codeforces Round #326 (Div. 1) C. Duff in the Army

来源:互联网 发布:linux查看普通用户 编辑:程序博客网 时间:2024/06/06 05:55

题目描述:

C. Duff in the Army
time limit per test4 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
Recently Duff has been a soldier in the army. Malek is her commander.

Their country, Andarz Gu has n cities (numbered from 1 to n) and n - 1 bidirectional roads. Each road connects two different cities. There exist a unique path between any two cities.

There are also m people living in Andarz Gu (numbered from 1 to m). Each person has and ID number. ID number of i - th person is i and he/she lives in city number ci. Note that there may be more than one person in a city, also there may be no people living in the city.

Malek loves to order. That’s why he asks Duff to answer to q queries. In each query, he gives her numbers v, u and a.

To answer a query:

Assume there are x people living in the cities lying on the path from city v to city u. Assume these people’s IDs are p1, p2, …, px in increasing order.

If k = min(x, a), then Duff should tell Malek numbers k, p1, p2, …, pk in this order. In the other words, Malek wants to know a minimums on that path (or less, if there are less than a people).

Duff is very busy at the moment, so she asked you to help her and answer the queries.

Input
The first line of input contains three integers, n, m and q (1 ≤ n, m, q ≤ 105).

The next n - 1 lines contain the roads. Each line contains two integers v and u, endpoints of a road (1 ≤ v, u ≤ n, v ≠ u).

Next line contains m integers c1, c2, …, cm separated by spaces (1 ≤ ci ≤ n for each 1 ≤ i ≤ m).

Next q lines contain the queries. Each of them contains three integers, v, u and a (1 ≤ v, u ≤ n and 1 ≤ a ≤ 10).

Output
For each query, print numbers k, p1, p2, …, pk separated by spaces in one line.

题解:

询问很多次,但是不修改.找出树上一条链的最小的10个数.每个树上结点有若干权值,保证都不一样.
第一反应是树链剖分+区间求最小10的值. 因为log太多,然而我们可以打st表. 方便的是每个权值都不一样,合并的时候相同的算一次就好.
答案的方法更好:类似于求lca的,保存到父亲的2^i的信息,然后每次算一下,只能够搞不修改的,但是不用额外的数据结构

重点:

只能有log * 10, 所以我们要利用好离线的性质

代码:

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <vector>using namespace std;const int maxn = 1e5 + 100;const int key = 10;struct aut{    int a[12];    aut() {    memset(a, 0, sizeof(a));    }};aut st[21][maxn];int n, no[maxn], fanno[maxn], L2[maxn], m, q;int fa[maxn], dep[maxn], top[maxn], siz[maxn], son[maxn], cnt;vector<int> G[maxn];void dfs1(int u, int pa) {    siz[u] = 1;    for(int i = 0; i < G[u].size(); i++) {        int v = G[u][i];    if(v != pa) {        dep[v] = dep[u] + 1;        fa[v] = u;        dfs1(v, u);        siz[u] += siz[v];        if(siz[v] > siz[son[u]])        son[u] = v;    }    }}void dfs2(int u, int tp) {    top[u] = tp;    ++cnt;    no[u] = cnt;    fanno[cnt] = u;    if(son[u]) {    dfs2(son[u], tp);    }    for(int i = 0; i < G[u].size(); i++) {    int v = G[u][i];    if(v != fa[u] && v != son[u]) {        dfs2(v, v);    }    }}aut getMerge(aut x, aut y) {    aut ans;    // printf("%d %d\n", x.a[0], y.a[0]);    int i = 0, j = 0, z = 0;    while(x.a[i] != 0 || y.a[j] != 0) {    //  printf("fasd %d\n", x.a[0]);    if(y.a[j] == 0 ||(x.a[i] != 0 && x.a[i] < y.a[j])) {        // printf("no\n");        ans.a[z] = x.a[i];        z++;        i++;    }    else if(x.a[i] == 0 || y.a[j] < x.a[i]) {        ans.a[z] = y.a[j];        z++;        j++;        //  printf("*****%d\n", ans.a[0]);    }    else {        //  printf("kao  %d %d\n", x.a[0], i);        ans.a[z] = x.a[i];        z++;        i++;        j++;    }    if(z >= key)        break;    }    //printf("%d\n", ans.a[0]);    return ans;}void getST() {    // st 0 already    //    printf("----- %d  %d\n", st[1][4].a[0], st[1][4].a[1]);    for(int s = 1; s <= 20; s++) {    for(int i = 1; i + (1 << s) - 1 <= n; i++) {        int j = i + (1 << (s - 1));    //printf("s %d  i %d\n", s, i);        st[s][i] = getMerge(st[s - 1][i], st[s - 1][j]);    }    }    //     printf("----- %d  %d\n", st[1][4].a[0], st[1][4].a[1]);}aut query(int l, int r) {    int len = r - l + 1;    int s = L2[len];    // printf("---- %d %d %d\n", l, r, s);    aut ans;    //printf("merge %d %d\n", st[s][l].a[0], st[s][l].a[1]);    ans = getMerge(st[s][l], st[s][r - (1 << s) + 1]);    //for(int i = 0; ans.a[i] != 0; i++)    //  printf("zzzzzzz %d ", ans.a[i]);    //    printf("\n");    return ans;}aut divide(int u, int v) {    int ut = top[u], vt = top[v];    aut ans;    while(ut != vt) {    if(dep[ut] < dep[vt]) {        swap(ut, vt);        swap(u, v);    }    ans = getMerge(ans, query(no[ut], no[u]));    u = fa[ut];    ut = top[u];    }    if(dep[u] < dep[v])    swap(u, v);    //printf("** %d %d\n", no[v], no[u]);    ans = getMerge(ans, query(no[v], no[u]));    return ans;}void solve() {    fa[1] = 0;    dep[1] = 0;    son[0] = 0;    siz[0] = 0;    dfs1(1, 0);    cnt = 0;    dfs2(1, 1);    for(int i = 1; i <= m; i++) {    int t;    scanf("%d", &t);    aut tmp;    tmp.a[0] = i;    st[0][no[t]] = getMerge(st[0][no[t]], tmp);    }    getST();    for(int i = 1;i <= q; i++) {    int u, v, a;    scanf("%d%d%d", &u, &v, &a);    aut ans = divide(u, v);    //printf("%d %d  %d\n", no[u], no[v], ans.a[0]);    int num = 0;    for(int j = 0; ans.a[j] != 0 && j < a; j++) {        num++;    }    printf("%d", num);    for(int j = 0; j < num; j++) {        printf(" %d", ans.a[j]);    }    printf("\n");    }}int main() {   //freopen("D.txt", "r", stdin);    L2[0] = -1;    for(int i = 1; i <= 100000; i++) {    if((i & (i - 1)) == 0)        L2[i] = L2[i - 1] + 1;    else        L2[i] = L2[i - 1];    }    while(scanf("%d%d%d", &n, &m, &q) != EOF) {    for(int i = 1; i <= n; i++) {        G[i].clear();    }    for(int i = 1; i <= n - 1; i++) {        int u, v;        scanf("%d%d", &u, &v);        G[u].push_back(v);        G[v].push_back(u);    }    solve();    }    return 0;}
0 0
原创粉丝点击