【Luogu 4178】Tree
阿新 • • 發佈:2018-11-17
col play 我們 hide nbsp spa esp 前綴 樹狀
Tree
點分治
題目鏈接:https://www.luogu.org/problemnew/show/P4178
對於點分治,我們每次處理一個重心的時候:
用b數組存這個重心處理到當前連邊兒子,以這個兒子為根的子樹,這顆子樹的每個節點到重心的路徑長
用p數組存這個重心所有連邊兒子的b數組(目的是為了清空g)
用g數組為樹狀數組存這個重心的到它所有連邊/非連邊兒子的路徑長前綴和
於是我們每次處理一個重心的一個兒子時
if(b[i]<=k)++;(此時統計不經過重心的答案)
if(b[i]>=k)continue;(b[i]==k continue 是因為此時k-b[i]==0,統計無意義)
ans+=∑sum(k-b[i]) (sum為g樹狀數組前綴和,此時統計經過這個重心的答案)
p[++top]=b[i];
add(b[i]);
每次處理完這個重心後,用p數組把樹狀數組清空即可(用p數組更省時間)
總時間為 點分治nlogn*樹狀數組logn=nlog^2n
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int M=100009; 5 int n,k,num=0,minn,rt,size,ans=0View Code,tot,top; 6 int head[M],siz[M],p[M],g[M],b[M]; 7 struct P{int to,ne,w;}e[M<<1]; 8 bool vis[M]; 9 int read(){ 10 int rex=0,f=1;char ch=getchar(); 11 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 12 while(ch>=‘0‘&&ch<=‘9‘){rex=rex*10+ch-‘0‘;ch=getchar();} 13 returnrex*f; 14 } 15 void getrt(int u,int fa){ 16 siz[u]=1;int ma=0; 17 for(int i=head[u];i;i=e[i].ne){ 18 int v=e[i].to;if(v==fa||vis[v])continue; 19 getrt(v,u);siz[u]+=siz[v];ma=max(ma,siz[v]); 20 } 21 ma=max(ma,size-siz[u]); 22 if(minn>ma){minn=ma,rt=u;} 23 } 24 void dfs(int u,int fa,int w){ 25 b[++tot]=w; 26 for(int i=head[u];i;i=e[i].ne){ 27 int v=e[i].to;if(v==fa||vis[v])continue; 28 dfs(v,u,w+e[i].w); 29 } 30 } 31 void add(int x,int y){ 32 for(;x<=k;x+=x&-x)g[x]+=y; 33 } 34 int sum(int x,int rex=0){ 35 for(;x;x-=x&-x)rex+=g[x]; 36 return rex; 37 } 38 void get(int v,int u,int w){ 39 tot=0; 40 dfs(v,u,w); 41 for(int i=1;i<=tot;++i){ 42 if(b[i]<=k)ans++; 43 if(b[i]>=k)continue; 44 p[++top]=b[i]; 45 ans+=sum(k-b[i]); 46 } 47 for(int i=1;i<=tot;++i){ 48 if(b[i]>=k)continue; 49 add(b[i],1); 50 } 51 } 52 void work(int u){ 53 vis[u]=1;top=0; 54 for(int i=head[u];i;i=e[i].ne){ 55 int v=e[i].to; 56 if(!vis[v])get(v,u,e[i].w); 57 } 58 for(int i=1;i<=top;++i)add(p[i],-1); 59 for(int i=head[u];i;i=e[i].ne){ 60 int v=e[i].to;if(vis[v])continue; 61 minn=1e9;size=siz[u]; 62 getrt(v,0); 63 work(rt); 64 } 65 } 66 int main(){ 67 n=read(); 68 for(int i=1,u,v,w;i<n;++i){ 69 u=read(),v=read(),w=read(); 70 e[++num]=(P){v,head[u],w};head[u]=num; 71 e[++num]=(P){u,head[v],w};head[v]=num; 72 } 73 k=read(); 74 minn=1e9;size=n; 75 getrt(1,0); 76 work(rt); 77 printf("%d",ans); 78 return 0; 79 }
【Luogu 4178】Tree