1. 程式人生 > >P3258 松鼠的新家

P3258 松鼠的新家

play style names bsp span als isp problem 實現題

松鼠的新家

洛谷鏈接

盡管標簽是省選/NOI-,但提交的通過率已經高到三分之一了。

但它仍舊是一個省選/NOI-的題。

大致題意就是按輸入的順序走一棵樹,看每個節點經過多少次。問題就相當於把一條鏈上的所有節點權值都加一,最後統計每個點的權值。

但這樣的時間復雜度比較高,所以我們可以把這條鏈的頭節點和尾節點的權值都加一,然後把它們的LCA減一,它們LCA的父親節點減一。之後每次通記每個節點都統計該節點及其子樹的權值和,就是這個節點被經過的次數。

而題目要求在最後的終點不需要計算,所以我們可以把“這條鏈的頭節點和尾節點的權值都加一”,改為“這條鏈的尾節點的父親和頭節點的權值都加一”,就可以實現題目要求。

技術分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #define N 300010
 4 using namespace std;
 5 int next[N*2],to[N*2],num,head[N],ans[N],size[N],father[N],top[N],sum[N],n,a,b,c,deep[N],haha[N];
 6 void add(int false_from,int false_to){
 7     next[++num]=head[false_from];
 8     to[num]=false_to;
9 head[false_from]=num; 10 } 11 void dfs1(int x){ 12 size[x]=1; 13 deep[x]=deep[father[x]]+1; 14 for(int i=head[x];i;i=next[i]) 15 if(father[x]!=to[i]){ 16 father[to[i]]=x; 17 dfs1(to[i]); 18 size[x]+=size[to[i]]; 19 } 20 } 21 void dfs2(int
x){ 22 int mmax=0; 23 if(!top[x]) 24 top[x]=x; 25 for(int i=head[x];i;i=next[i]) 26 if(father[x]!=to[i]&&size[to[i]]>size[mmax]) 27 mmax=to[i]; 28 if(mmax){ 29 top[mmax]=top[x]; 30 dfs2(mmax); 31 } 32 for(int i=head[x];i;i=next[i]) 33 if(father[x]!=to[i]&&to[i]!=mmax) 34 dfs2(to[i]); 35 } 36 void dfs3(int x){ 37 ans[x]=sum[x]; 38 for(int i=head[x];i;i=next[i]) 39 if(father[x]!=to[i]){ 40 dfs3(to[i]); 41 ans[x]+=ans[to[i]]; 42 } 43 } 44 int lca(int x,int y){ 45 while(top[x]!=top[y]){ 46 if(deep[top[x]]<deep[top[y]]) 47 swap(x,y); 48 x=father[top[x]]; 49 } 50 if(deep[x]<deep[y]) 51 return x; 52 return y; 53 } 54 int main(){ 55 scanf("%d",&n); 56 for(int i=1;i<=n;++i) 57 scanf("%d",&haha[i]); 58 for(int i=1;i<n;++i){ 59 scanf("%d%d",&a,&b); 60 add(a,b); 61 add(b,a); 62 } 63 dfs1(1); 64 dfs2(1); 65 for(int i=1;i<n;++i){ 66 a=haha[i]; 67 b=haha[i+1]; 68 c=lca(a,b); 69 sum[a]++; 70 sum[father[b]]++; 71 sum[c]--; 72 sum[father[c]]--; 73 } 74 dfs3(1); 75 for(int i=1;i<=n;++i) 76 printf("%d\n",ans[i]); 77 return 0; 78 }
View Code

P3258 松鼠的新家