Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
A1505. 树(张闻涛)
试题来源
2013中国国家集训队第二次作业
问题描述
给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的中位数,k个数的中位数定义为从0到k-1编号从小到大排序后k/2号的那个数。
输入格式
第一行两个整数N,M
第二行N个整数,v[1]~v[n],代表每个节点的权值。
接下来N-1行每行两个整数x,y代表x和y有一条边
最后M行每行三个整数a,b,c,表示一组询问。
第二行N个整数,v[1]~v[n],代表每个节点的权值。
接下来N-1行每行两个整数x,y代表x和y有一条边
最后M行每行三个整数a,b,c,表示一组询问。
输出格式
共M行,每行一个整数,代表询问的答案。
样例输入
5 3
1 3 2 4 5
1 2
2 4
4 3
4 5
1 1 5
2 1 3
3 1 5
1 3 2 4 5
1 2
2 4
4 3
4 5
1 1 5
2 1 3
3 1 5
样例输出
1
4
4
4
4
数据规模和约定
共20个数据
数据1~3 N,M<=1000
数据4~6 N,M<=5000
数据7~10 N,M<=10000
数据11~18 N,M<=30000
数据19~20 N,M<=100000
数据1~3 N,M<=1000
数据4~6 N,M<=5000
数据7~10 N,M<=10000
数据11~18 N,M<=30000
数据19~20 N,M<=100000
题解:
倍增LCA+可持久化线段树+DFS序
直接把可持久化线段树建到DFS序上即可。
每个点由其 父亲结点 为基础建立即可。
设询问 u -> v 路径,路径上点数为k个。
然后若a=1,输出链上排第一小的。
a=2,输出链上排第k小的。
a=3,输出链上排第k/2+1小的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 100010 4 struct node 5 { 6 int begin,end,next; 7 }edge[MAXN*2]; 8 struct NODE 9 { 10 int left,right; 11 }tree[MAXN*20]; 12 int cnt,Head[MAXN],SIZE,deep[MAXN],P[MAXN][17],tot,root[MAXN],n,sum[MAXN*20],val[MAXN],cc[MAXN],pos[MAXN],value[MAXN]; 13 bool vis[MAXN]; 14 void addedge(int bb,int ee) 15 { 16 edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt; 17 } 18 void addedge1(int bb,int ee) 19 { 20 addedge(bb,ee);addedge(ee,bb); 21 } 22 int read() 23 { 24 int s=0,fh=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 27 return s*fh; 28 } 29 void dfs(int u) 30 { 31 int i,v; 32 vis[u]=true; 33 SIZE++;pos[u]=SIZE;value[SIZE]=u; 34 for(i=Head[u];i!=-1;i=edge[i].next) 35 { 36 v=edge[i].end; 37 if(vis[v]==false) 38 { 39 deep[v]=deep[u]+1; 40 P[v][0]=u; 41 dfs(v); 42 } 43 } 44 } 45 void Ycl() 46 { 47 int i,j; 48 for(j=1;(1<<j)<=n;j++) 49 { 50 for(i=1;i<=n;i++) 51 { 52 if(P[i][j-1]!=-1)P[i][j]=P[P[i][j-1]][j-1]; 53 } 54 } 55 } 56 int LCA(int x,int y) 57 { 58 if(deep[x]<deep[y])swap(x,y); 59 int i,j; 60 for(i=0;(1<<i)<=deep[x];i++);i--; 61 for(j=i;j>=0;j--)if(deep[x]-(1<<j)>=deep[y])x=P[x][j]; 62 if(x==y)return x; 63 for(j=i;j>=0;j--) 64 { 65 if(P[x][j]!=-1&&P[x][j]!=P[y][j]) 66 { 67 x=P[x][j]; 68 y=P[y][j]; 69 } 70 } 71 return P[x][0]; 72 } 73 void Build(int x,int &y,int l,int r,int B) 74 { 75 y=++SIZE; 76 sum[y]=sum[x]+1; 77 if(l==r)return; 78 tree[y].left=tree[x].left;tree[y].right=tree[x].right; 79 int mid=(l+r)/2; 80 if(B<=mid)Build(tree[x].left,tree[y].left,l,mid,B); 81 else Build(tree[x].right,tree[y].right,mid+1,r,B); 82 } 83 int Query(int l,int r,int A,int B,int C,int D,int Q) 84 { 85 if(l==r)return l; 86 int mid,delta=sum[tree[A].left]+sum[tree[B].left]-sum[tree[C].left]-sum[tree[D].left]; 87 mid=(l+r)/2; 88 if(Q<=delta)return Query(l,mid,tree[A].left,tree[B].left,tree[C].left,tree[D].left,Q); 89 else return Query(mid+1,r,tree[A].right,tree[B].right,tree[C].right,tree[D].right,Q-delta); 90 } 91 int query(int u,int v,int lca,int k) 92 { 93 int A=pos[u],B=pos[v],C=pos[lca],D=pos[P[lca][0]]; 94 return Query(1,tot,root[A],root[B],root[C],root[D],k); 95 } 96 int main() 97 { 98 int m,i,wz,s1,s2,s3,lca,k,bb,ee; 99 n=read();m=read(); 100 for(i=1;i<=n;i++)val[i]=read(),cc[i]=val[i]; 101 sort(cc+1,cc+n+1); 102 tot=unique(cc+1,cc+n+1)-(cc+1); 103 memset(Head,-1,sizeof(Head));cnt=1; 104 for(i=1;i<n;i++){bb=read();ee=read();addedge1(bb,ee);} 105 memset(P,-1,sizeof(P)); 106 SIZE=0; 107 dfs(1);Ycl(); 108 SIZE=0; 109 for(i=1;i<=n;i++)//按树上顺序插入. 110 { 111 k=value[i]; 112 wz=lower_bound(cc+1,cc+tot+1,val[k])-cc; 113 Build(root[pos[P[k][0]]],root[i],1,tot,wz); 114 } 115 SIZE=0; 116 for(i=1;i<=m;i++) 117 { 118 s1=read();s2=read();s3=read(); 119 if(s1==1){lca=LCA(s2,s3);printf("%d\n",cc[query(s2,s3,lca,1)]);} 120 else if(s1==2){lca=LCA(s2,s3);k=deep[s2]+deep[s3]-2*deep[lca]+1;printf("%d\n",cc[query(s2,s3,lca,k)]);} 121 else {lca=LCA(s2,s3);k=(deep[s2]+deep[s3]-2*deep[lca]+3)/2;printf("%d\n",cc[query(s2,s3,lca,k)]);} 122 } 123 fclose(stdin); 124 fclose(stdout); 125 return 0; 126 }