1. 程式人生 > >解題:洛谷4178 Tree

解題:洛谷4178 Tree

題面

重(新)學點分治中......

普通的點分治一般這幾步:

1.找重心

2.從重心開始DFS,得到資訊

3.統計經過重心的路徑

4.分別分治幾棵子樹,繼續這個過程

然後是常見的(制杖的我的)一些疑問

1.這麼統計不會漏嗎

不會,你遞迴進子樹的時候經過當前重心的已經統計完了,分別統計子樹就行

2.這麼統計不會重嗎

不會,因為你進子樹不會往回走(這倆都是啥問題啊。。。)

3.複雜度?

$O(n\log n)$,根據重心的性質可得

這個題把所有路徑排個序然後雙指標掃即可,複雜度$O(n\log n)$

 1 #include<cstdio>
 2
#include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=40005,inf=1e9; 6 int siz[N],vis[N],dis[N],mem[N]; 7 int p[N],noww[2*N],goal[2*N],val[2*N]; 8 int n,k,c,t1,t2,t3,cnt,lp,rp,nsiz,maxx; 9 long long ans; 10 void Link(int f,int t,int v) 11 { 12 noww[++cnt]=p[f],p[f]=cnt;
13 goal[cnt]=t,val[cnt]=v; 14 } 15 void Mark(int nde,int fth) 16 { 17 siz[nde]=1; int tmp=0; 18 for(int i=p[nde];i;i=noww[i]) 19 if(goal[i]!=fth&&!vis[goal[i]]) 20 { 21 Mark(goal[i],nde); 22 siz[nde]+=siz[goal[i]]; 23 tmp=max(tmp,siz[goal[i]]);
24 } 25 tmp=max(tmp,nsiz-siz[nde]); 26 if(tmp<maxx) maxx=tmp,c=nde; 27 } 28 void DFS(int nde,int fth) 29 { 30 mem[++rp]=dis[nde]; 31 for(int i=p[nde];i;i=noww[i]) 32 if(goal[i]!=fth&&!vis[goal[i]]) 33 { 34 dis[goal[i]]=dis[nde]+val[i]; 35 DFS(goal[i],nde); 36 } 37 } 38 int Getans(int nde,int fir) 39 { 40 lp=1,rp=0,dis[nde]=fir,DFS(nde,0); 41 long long ret=0; 42 sort(mem+1,mem+1+rp); 43 while(lp<rp) 44 (mem[lp]+mem[rp]<=k)?ret+=rp-lp,lp++:rp--; 45 return ret; 46 } 47 void PDC(int nde) 48 { 49 ans+=Getans(nde,0),vis[nde]=true; 50 for(int i=p[nde];i;i=noww[i]) 51 if(!vis[goal[i]]) 52 { 53 ans-=Getans(goal[i],val[i]); 54 nsiz=siz[goal[i]],maxx=inf; 55 Mark(goal[i],0),PDC(c); 56 } 57 } 58 int main() 59 { 60 scanf("%d",&n); 61 for(int i=1;i<n;i++) 62 { 63 scanf("%d%d%d",&t1,&t2,&t3); 64 Link(t1,t2,t3),Link(t2,t1,t3); 65 } 66 scanf("%d",&k),nsiz=n,maxx=inf; 67 Mark(1,0),PDC(c),printf("%lld",ans); 68 return 0; 69 }
View Code