1. 程式人生 > >[CF832D] Misha, Grisha and Underground

[CF832D] Misha, Grisha and Underground

人生 div spa for ret int ont alt calc

題意:給一棵樹,若指定三點(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 }

[CF832D] Misha, Grisha and Underground