题意:给一棵树,若指定三点(f,s,t),泽先江f到s的每一个点染色,答案为f到t路径上染色点的个数
现在给定多组询问(a,b,c),从中确定(f,s,t)使答案最大
这题考场上我居然想了出来并且1A了2333(人生第一次独立做出D绝对不是它太水)
首先让a,b,c分别作为f,取最大的答案
问题变为:已知f,s,t的位置,如何统计答案
分三类讨论(图中f为红色点,棕色路径为答案)
lca(f,s)==lca(f,t)
lca(f,t)==lca(s,t)
lca(f,s)==lca(s,t)
然后统计答案时只需用倍增求各种lca就行了
1 #include<stdio.h> 2 struct edge{ 3 int to,next; 4 }e[200010]; 5 int n,tot,h[100010],dep[100010],fa[100010][21]; 6 void add(int a,int b){ 7 tot++; 8 e[tot].to=b; 9 e[tot].next=h[a]; 10 h[a]=tot; 11 } 12 void dfs(int f,int x){ 13 fa[x][0]=f; 14 dep[x]=dep[f]+1; 15 for(int i=h[x];i;i=e[i].next){ 16 if(e[i].to!=f)dfs(x,e[i].to); 17 } 18 } 19 void swap(int&a,int&b){ 20 a^=b^=a^=b; 21 } 22 int lca(int x,int y){ 23 if(dep[x]<dep[y])swap(x,y); 24 int i; 25 for(i=20;i>=0;i--){ 26 if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; 27 } 28 if(x==y)return x; 29 for(i=20;i>=0;i--){ 30 if(fa[x][i]!=fa[y][i]){ 31 x=fa[x][i]; 32 y=fa[y][i]; 33 } 34 } 35 return fa[x][0]; 36 } 37 int max(int a,int b){return a>b?a:b;} 38 int calc(int f,int s,int t){ 39 int fs,ft,st,fst; 40 fs=lca(f,s); 41 ft=lca(f,t); 42 st=lca(s,t); 43 fst=lca(fs,ft); 44 if(fs==ft)return dep[f]+dep[st]-2*dep[fst]+1; 45 if(fs==st)return dep[f]-dep[ft]+1; 46 return dep[f]-dep[fs]+1; 47 } 48 int main(){ 49 int q,i,j,a,b,c; 50 scanf("%d%d",&n,&q); 51 for(i=2;i<=n;i++){ 52 scanf("%d",&a); 53 add(a,i); 54 add(i,a); 55 } 56 dep[0]=-1; 57 dfs(0,1); 58 for(j=1;j<21;j++){ 59 for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; 60 } 61 while(q--){ 62 scanf("%d%d%d",&a,&b,&c); 63 printf("%d\n",max(max(calc(a,b,c),calc(b,a,c)),calc(c,a,b))); 64 } 65 }
时间: 2024-10-30 21:38:25