【Luogu 4178】Tree

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=0,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     return rex*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 }
View Code

 

  

 

posted @ 2018-11-17 17:15  sjie  阅读(237)  评论(0编辑  收藏  举报