树分治入门:例题poj1741

题目链接:Tree

树分治参考资料:09年漆子超  ZigZagK的博客 【点分治】的学习笔记和众多例题

以上的资料是我看过好的,具体算法分析实现都讲明白.

 1 //#include<bits/stdc++.h>
 2 #include<set>
 3 #include<cstdio>
 4 #include<iomanip>
 5 #include<iostream>
 6 #include<string>
 7 #include<cstring>
 8 #include<algorithm>
 9 #define pb push_back
10 #define ll long long
11 #define fi first
12 #define se second
13 #define PI 3.14159265
14 #define ls l,m,rt<<1
15 #define rs m+1,r,rt<<1|1
16 #define eps 1e-7
17 #define pii pair<int,int>
18 typedef unsigned long long ull;
19 const int mod=1e3+5;
20 const ll inf=0x3f3f3f3f3f3f3f;
21 const int maxn=1e5+5;
22 using namespace std;
23 int n,m,head[maxn],to[maxn*2],w[maxn*2],nxt[maxn*2],cnt,k,siz[maxn],dep[maxn],rt,mx[maxn],s;
24 int now[maxn];
25 bool vis[maxn];
26 ll ans;
27 void add_edge(int x,int y,int l)
28 {
29     to[++cnt]=y;w[cnt]=l;nxt[cnt]=head[x];head[x]=cnt;
30 }
31 void dfs_rt(int v,int f)//找重心
32 {
33     siz[v]=1;mx[v]=0;
34     //cout<<v<<"SSS"<<f<<endl;
35     for(int i=head[v];i;i=nxt[i])
36     {
37         if(to[i]==f||vis[to[i]])continue;
38         dfs_rt(to[i],v);
39         siz[v]+=siz[to[i]];
40         mx[v]=max(siz[to[i]],mx[v]);
41     }
42     mx[v]=max(s-siz[v],mx[v]);
43     if(rt==-1||mx[v]<mx[rt])rt=v;
44 }
45 void get_dep(int v,int f)
46 {
47     now[++now[0]]=dep[v];
48     for(int i=head[v];i;i=nxt[i])
49     {
50         if(vis[to[i]]||to[i]==f)continue;
51         dep[to[i]]=dep[v]+w[i];
52         get_dep(to[i],v);
53     }
54 }
55 int  get_sum(int v,int dis)
56 {
57     int cn=0;now[0]=0;
58     dep[v]=dis;get_dep(v,-1);
59     sort(now+1,now+1+now[0]);
60     int l=1,r=now[0];
61     while(l<r)if(now[l]+now[r]<=k)cn+=r-l,l++;else r--;
62     return cn;
63 }
64 void get_ans(int v)
65 {
66     vis[v]=true;ans+=get_sum(v,0);
67     for(int i=head[v];i;i=nxt[i])
68     {
69         if(vis[to[i]])continue;
70         ans-=get_sum(to[i],w[i]);
71         rt=-1;s=siz[to[i]];dfs_rt(to[i],v);
72         get_ans(rt);
73     }
74 }
75 int main()
76 {
77     while(~scanf("%d %d",&n,&k))
78     {
79         if(!n&&!k)break;
80         memset(head,0,sizeof(head));cnt=0;ans=0;
81         memset(vis,0,sizeof(vis));
82         for(int i=0;i<n-1;i++)
83         {
84             int u,v,l;
85             scanf("%d %d %d",&u,&v,&l);
86             add_edge(u,v,l);add_edge(v,u,l);
87         }
88         rt=-1;s=n;dfs_rt(1,-1);
89         get_ans(rt);
90         printf("%lld\n",ans);
91     }
92     return 0;
93 }

第二个例题:2152: 聪聪可可

题解:跟上面那题差不多,计算出的到根的距离%3之后的值的个数,now[0],now[1],now[2].答案就是now[0]*now[0]+2*now[1]*now[2]

 1 #include<bits/stdc++.h>
 2 #include<set>
 3 #include<cstdio>
 4 #include<iomanip>
 5 #include<iostream>
 6 #include<string>
 7 #include<cstring>
 8 #include<algorithm>
 9 #define pb push_back
10 #define ll long long
11 #define fi first
12 #define se second
13 #define PI 3.14159265
14 #define ls l,m,rt<<1
15 #define rs m+1,r,rt<<1|1
16 #define eps 1e-7
17 #define pii pair<int,int>
18 typedef unsigned long long ull;
19 const int mod=1e3+5;
20 const ll inf=0x3f3f3f3f3f3f3f;
21 const int maxn=2e4+5;
22 using namespace std;
23 int n,m,head[maxn],to[maxn*2],w[maxn*2],nxt[maxn*2],cnt,k,siz[maxn],dep[maxn],rt,mx[maxn],s;
24 int now[maxn];
25 bool vis[maxn];
26 int ans;
27 void add_edge(int x,int y,int l)
28 {
29     to[++cnt]=y;w[cnt]=l;nxt[cnt]=head[x];head[x]=cnt;
30 }
31 void dfs_rt(int v,int f)//找重心
32 {
33     siz[v]=1;mx[v]=0;
34     for(int i=head[v];i;i=nxt[i])
35     {
36         if(to[i]==f||vis[to[i]])continue;
37         dfs_rt(to[i],v);
38         siz[v]+=siz[to[i]];
39         mx[v]=max(siz[to[i]],mx[v]);
40     }
41     mx[v]=max(s-siz[v],mx[v]);
42     if(rt==-1||mx[v]<mx[rt])rt=v;
43 }
44 void get_dep(int v,int f)
45 {
46     now[(dep[v])%3]++;
47     for(int i=head[v];i;i=nxt[i])
48     {
49         if(vis[to[i]]||to[i]==f)continue;
50         dep[to[i]]=dep[v]+w[i];
51         get_dep(to[i],v);
52     }
53 }
54 int  get_sum(int v,int dis)
55 {
56     int cn=0;now[0]=0,now[1]=0,now[2]=0;
57     dep[v]=dis;get_dep(v,-1);
58     cn+=now[0]*now[0]+2*now[1]*now[2];
59     return cn;
60 }
61 void get_ans(int v)
62 {
63     vis[v]=true;ans+=get_sum(v,0);
64     for(int i=head[v];i;i=nxt[i])
65     {
66         if(vis[to[i]])continue;
67         ans-=get_sum(to[i],w[i]);
68         rt=-1;s=siz[to[i]];dfs_rt(to[i],v);
69         get_ans(rt);
70     }
71 }
72 int main()
73 {
74     while(~scanf("%d",&n))
75     {
76         memset(head,0,sizeof(head));cnt=0;
77         memset(vis,0,sizeof(vis));
78         for(int i=0;i<n-1;i++)
79         {
80             int u,v,l;
81             scanf("%d %d %d",&u,&v,&l);
82             add_edge(u,v,l);add_edge(v,u,l);
83         }
84         rt=-1;s=n;dfs_rt(1,-1);
85         get_ans(rt);
86         int sum=n*n;
87         int tmp=__gcd(sum,ans);
88 
89         ans/=tmp;sum/=tmp;
90         printf("%d/%d\n",ans,sum);
91     }
92     return 0;
93 }
View Code

第三个题: 1316: 树上的询问

在一次树分治的过程中统计到重心的距离,对于每一个q[i]枚举一个点然后二分去找q[i]-dep[i]的个数用lower_bound 和upper_bound相减就可以来。10sec.我9988ms卡过,,,,运气不好就t了

  1 #include<bits/stdc++.h>
  2 #include<set>
  3 #include<cstdio>
  4 #include<iomanip>
  5 #include<iostream>
  6 #include<string>
  7 #include<cstring>
  8 #include<algorithm>
  9 #define pb push_back
 10 #define ll long long
 11 #define fi first
 12 #define se second
 13 #define PI 3.14159265
 14 #define ls l,m,rt<<1
 15 #define rs m+1,r,rt<<1|1
 16 #define eps 1e-7
 17 #define pii pair<int,int>
 18 typedef unsigned long long ull;
 19 const int mod=1e3+5;
 20 const ll inf=0x3f3f3f3f3f3f3f;
 21 const int maxn=2e4+5;
 22 using namespace std;
 23 int n,m,head[maxn],to[maxn*2],w[maxn*2],nxt[maxn*2],cnt,siz[maxn],dep[maxn],rt,mx[maxn],s,q;
 24 int now[maxn],ans[120],que[120];
 25 bool vis[maxn];
 26 void add_edge(int x,int y,int l)
 27 {
 28     to[++cnt]=y;w[cnt]=l;nxt[cnt]=head[x];head[x]=cnt;
 29 }
 30 void dfs_rt(int v,int f)//找重心
 31 {
 32     siz[v]=1;mx[v]=0;
 33     for(int i=head[v];i;i=nxt[i])
 34     {
 35         if(to[i]==f||vis[to[i]])continue;
 36         dfs_rt(to[i],v);
 37         siz[v]+=siz[to[i]];
 38         mx[v]=max(siz[to[i]],mx[v]);
 39     }
 40     mx[v]=max(s-siz[v],mx[v]);
 41     if(rt==-1||mx[v]<mx[rt])rt=v;
 42 }
 43 void get_dep(int v,int f)
 44 {
 45     now[++now[0]]=dep[v];
 46     for(int i=head[v];i;i=nxt[i])
 47     {
 48         if(vis[to[i]]||to[i]==f)continue;
 49         dep[to[i]]=dep[v]+w[i];
 50         get_dep(to[i],v);
 51     }
 52 }
 53 int  get_sum(int v,int dis,int k)
 54 {
 55     int cn=0;now[0]=0;
 56     dep[v]=dis;get_dep(v,-1);
 57     sort(now+1,now+1+now[0]);
 58     for(int i=1;i<=now[0];i++)
 59     {
 60         if(now[i]*2>k)break;
 61         cn+=upper_bound(now+1,now+1+now[0],k-now[i])-lower_bound(now+1,now+1+now[0],k-now[i]);
 62     }
 63     return cn;
 64 }
 65 void get_ans(int v)
 66 {
 67     vis[v]=true;
 68     for(int i=1;i<=q;i++)ans[i]+=get_sum(v,0,que[i]);
 69     for(int i=head[v];i;i=nxt[i])
 70     {
 71         if(vis[to[i]])continue;
 72         for(int j=1;j<=q;j++)ans[j]-=get_sum(to[i],w[i],que[j]);
 73         rt=-1;s=siz[to[i]];dfs_rt(to[i],v);
 74         get_ans(rt);
 75     }
 76 }
 77 int main()
 78 {
 79         scanf("%d %d",&n,&q);
 80         for(int i=0;i<n-1;i++)
 81         {
 82             int u,v,l;
 83             scanf("%d %d %d",&u,&v,&l);
 84             add_edge(u,v,l);add_edge(v,u,l);
 85         }
 86         for(int i=1;i<=q;i++)
 87         {
 88             scanf("%d",&que[i]);
 89         }
 90         rt=-1;s=n;dfs_rt(1,-1);
 91         get_ans(rt);
 92         for(int i=1;i<=q;i++)
 93         {
 94             if(ans[i])
 95             {
 96                 printf("Yes\n");
 97             }
 98             else printf("No\n");
 99         }
100     return 0;
101 }
View Code

 

posted @ 2018-07-21 09:57  lhclqslove  阅读(180)  评论(0编辑  收藏  举报