Network
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 847 Accepted Submission(s): 347
Problem Description
The
ALPC company is now working on his own network system, which is
connecting all N ALPC department. To economize on spending, the backbone
network has only one router for each department, and N-1 optical fiber
in total to connect all routers.
The usual way to measure connecting
speed is lag, or network latency, referring the time taken for a sent
packet of data to be received at the other end.
Now the network is on
trial, and new photonic crystal fibers designed by ALPC42 is trying
out, the lag on fibers can be ignored. That means, lag happened when
message transport through the router. ALPC42 is trying to change routers
to make the network faster, now he want to know that, which router, in
any exactly time, between any pair of nodes, the K-th high latency is.
He needs your help.
Input
There are only one test case in input file.
Your
program is able to get the information of N routers and N-1 fiber
connections from input, and Q questions for two condition: 1. For some
reason, the latency of one router changed. 2. Querying the K-th longest
lag router between two routers.
For each data case, two integers N and Q for first line. 0<=N<=80000, 0<=Q<=30000.
Then n integers in second line refer to the latency of each router in the very beginning.
Then N-1 lines followed, contains two integers x and y for each, telling there is a fiber connect router x and router y.
Then
q lines followed to describe questions, three numbers k, a, b for each
line. If k=0, Telling the latency of router a, Ta changed to b; if
k>0, asking the latency of the k-th longest lag router between a and b
(include router a and b). 0<=b<100000000.
A blank line follows after each case.
Output
For
each question k>0, print a line to answer the latency time. Once
there are less than k routers in the way, print "invalid request!"
instead.
Sample Input
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
Sample Output
3
2
2
invalid request!
题意:给出n个点,m条询问,依次输入n个点都有权值,以及n-1条边,接下来m条询问每次输入 k a b如果 k=0 ,则更新a点的权值为b,如果k>0,则输出a-b这条路径上权值第K大的点,如果没有第K大点,输出invalid request!
今天做这个题,正好借这个题总结一下LCA的在线算法。
上图为测试用例:
LCA的在线算法,先要对此树进行预处理(为以后的RMQ做准备),即进行深搜。
我们设立三个数组:ver,first,deep ver数组保存树的前序遍历结点的结果,first保存结点第一次出现的位置,deep保存每个节点出现的深度
对此树进行先序遍历:
ver: 1 2 1 3 4 3 5 3 1
deep:1 2 1 2 3 2 3 2 1
first:1 2 4 5 7
从这里可以知道 ver和deep都要开两倍大小。
然后如果查询结点 2 5,先找到2以及5第一次出现的位置,first[2] = 2,first[5] = 7
那么2和5的最近公共祖先必定在ver[2]-ver[7]区间中。那么接下来,我们只要拿出这段区间内深度最小的点,那么这个点就肯定是2 5的最近公共祖先了
所以这里找区间最小值我们就可以利用RMQ算法了(这里RMQ的数组保存的是下标,因为deep和ver数组是通过下标联系起来的)。找到了2 1 2 3 2 3中
深度最小的是deep[3],对应ver中的ver[3]=1,所以2 和 5的最近公共祖先是1
RMQ算法:http://dongxicheng.org/structure/lca-rmq/
了解了过程,代码也就能够写出来了。
然后关于这题:我们要找a - b中的第K大点,那么我们记录一个父亲数组,u->lca,v->lca反着找就OK。
/* 5 5 5 1 2 3 4 3 1 2 1 4 3 5 3 2 4 5 */ #include<iostream> #include<cstdio> #include<algorithm> #include <string.h> #include <math.h> #define N 80005 using namespace std; struct Edge{ int u,v,next; }edge[2*N]; int head[N]; int deep[2*N]; int vis[N]; int first[N]; int ver[2*N]; int father[N]; int dp[2*N][25]; int value[N]; int path[N]; int tot; void add_edge(int u,int v,int &k){ ///Á´Ê½Ç°ÏòÐÇ edge[k].u = u,edge[k].v = v; edge[k].next = head[u];head[u] = k++; } void dfs(int u,int dep,int pre){ vis[u]=true,ver[++tot]=u,first[u]=tot,deep[tot]=dep,father[u]=pre; for(int k=head[u];k!=-1;k=edge[k].next){ if(!vis[edge[k].v]){ dfs(edge[k].v,dep+1,u); ver[++tot] = u,deep[tot]=dep; } } } int MIN(int i,int j){ if(deep[i]<deep[j]) return i; return j; } void init_RMQ(int n){ for(int i=1;i<=n;i++) dp[i][0]=i; for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ dp[i][j] = MIN(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int RMQ(int L,int R){ int k = (int)(log(R-L+1.0)/log(2.0)); int a = dp[L][k]; int b = dp[R-(1<<k)+1][k]; return MIN(a,b); } int LCA(int a,int b){ int x = first[a],y = first[b]; //printf("%d %d\n",deep[x],deep[y]); if(x>y) swap(x,y); //printf("RMQ(x,y): %d\n",RMQ(x,y)); return ver[RMQ(x,y)]; } int cmp(int a,int b){ return a>b; } void solve(int k,int u,int v){ int lca = LCA(u,v); tot=0; while(u!=lca){ path[tot++] = value[u]; u = father[u]; } while(v!=lca){ path[tot++] = value[v]; v = father[v]; } //printf("lca = %d\n",lca); path[tot++] = value[lca]; //printf("path[tot-1] = %d\n",path[tot-1]); if(k>tot){ printf("invalid request!\n"); return; } sort(path,path+tot,cmp); //for(int i=0;i<tot;i++) printf("%d ",path[i]); printf("%d\n",path[k-1]); } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF){ memset(head,-1,sizeof(head)); memset(father,-1,sizeof(father)); for(int i=1;i<=n;i++){ scanf("%d",&value[i]); } tot = 0; for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add_edge(u,v,tot); add_edge(v,u,tot); } tot = 0; dfs(1,1,-1); init_RMQ(2*n-1); while(m--){ int k,a,b; scanf("%d%d%d",&k,&a,&b); if(k==0){ value[a]=b; }else{ solve(k,a,b); } } } return 0; }