HDU 3078 — Network

来源:互联网 发布:apache logo 编辑:程序博客网 时间:2024/06/06 01:20

原题:http://acm.hdu.edu.cn/showproblem.php?pid=3078

题意:有n个点,Q个操作;

    给出n个点的权值,接下来n-1行给定一棵树;

    操作分两种:1、若k = 0,则将a的权值变成b的;

    2、若k > 0,则求出a到b路径上权值第k大的数;


思路:分别从u、v登山式的爬向lca(u, v),沿途记录每个点的权值;

    对所记录的权值进行排序;



#include<stdio.h>#include<queue>#include<set>#include<iostream>#include<algorithm>#include<string.h>using namespace std;queue<int>q;const int N = 80005;int dep[N], fa[N][20];int head[N];int val[N], arr[N];int e, k, ans;struct node{int to, nex;}edge[N<<1];void add(int u, int v){edge[e].to = v;edge[e].nex = head[u];head[u] = e++;}void bfs(int root){fa[root][0] = root;dep[root] = 0;q.push(root);while(!q.empty()){int u = q.front();q.pop();for(int i = 1;i<20;i++)fa[u][i] = fa[fa[u][i-1]][i-1];for(int i = head[u];i!=-1;i = edge[i].nex){int v = edge[i].to;if(v == fa[u][0])continue;dep[v] = dep[u]+1;fa[v][0] = u;q.push(v);}}}int lca(int x, int y){if(dep[x]<dep[y])swap(x, y);for(int i = 0;i<20;i++){if((dep[x]-dep[y])&(1<<i))x = fa[x][i];}if(x == y)return x;for(int i = 19;i>=0;i--){if(fa[x][i]!=fa[y][i]){x = fa[x][i];y = fa[y][i];}}return fa[x][0];}bool find(int l, int a, int b){set<int>s;s.clear();set<int>::iterator iter;int t = 0;arr[++t] = val[a];while(a!=l){a = fa[a][0];arr[++t] = val[a];}arr[++t] = val[b];while(b!=l){b = fa[b][0];if(b == l)break;arr[++t] = val[b];}if(t<k)return false;for(int i = 1;i<=t;i++)s.insert(arr[i]);int j = 1;for(iter = s.begin();iter!=s.end();++iter)    {    if(j == (t-k+1))    {    ans = *iter;    break;    }    j++;    }return true;}int main(){int n, Q;int cas = 0;while(scanf("%d%d", &n, &Q)!=EOF){if(cas++)printf("\n");memset(head, -1, sizeof(head));e = 0;for(int i = 1;i<=n;i++)scanf("%d", &val[i]);while(--n){int a, b;scanf("%d%d", &a, &b);add(a, b);add(b, a);}bfs(1);while(Q--){int a, b;scanf("%d%d%d", &k, &a, &b);if(k == 0)val[a] = val[b];if(k>0){int l = lca(a, b);if(find(l, a, b))printf("%d\n", ans);elseprintf("invalid request!\n");}}}return 0;}


0 0