这是 [点分治] 点分治入门 和 [模板] 点分治 的题解
入口:
[点分治] 点分治入门 : https://www.cnblogs.com/Railgun000/p/12597057.html
[模板] 点分治 : https://www.cnblogs.com/Railgun000/p/12810246.html
配套训练赛:https://vjudge.net/contest/362994#overview
题单:
题解:
A - Balancing Act
1 #include<stdio.h> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const int amn=1e5+5,inf=2e9; 7 8 int n; 9 10 int head[amn],etot; 11 struct edge{ 12 int nxt,v; 13 edge(){} 14 edge(int nxt,int v):nxt(nxt),v(v){} 15 }eg[amn]; 16 void init(){ 17 etot=0; 18 memset(head,0,sizeof head); 19 } 20 void add(int u,int v){ 21 eg[++etot]=edge(head[u],v); 22 head[u]=etot; 23 } 24 25 int siz[amn],maxt[amn]; 26 void calsiz(int u,int fa,int sum){ 27 siz[u]=1; 28 maxt[u]=0; 29 for(int i=head[u];i;i=eg[i].nxt){ 30 int v=eg[i].v; 31 if(v==fa)continue; 32 calsiz(v,u,sum); 33 siz[u]+=siz[v]; 34 maxt[u]=max(maxt[u],siz[v]); 35 } 36 maxt[u]=max(maxt[u],sum-siz[u]); 37 } 38 39 int main(){ 40 int t;scanf("%d",&t); 41 int u,v,ans1,ans2; 42 while(t--){ 43 init(); 44 scanf("%d",&n); 45 for(int i=1;i<n;i++){ 46 scanf("%d%d",&u,&v); 47 add(u,v); 48 add(v,u); 49 } 50 calsiz(1,-1,n); 51 ans2=inf; 52 for(int i=1;i<=n;i++){ 53 if(maxt[i]<ans2){ 54 ans1=i; 55 ans2=maxt[i]; 56 } 57 } 58 printf("%d %d ",ans1,ans2); 59 } 60 } 61 62 /** 63 题意: 64 给一个树, 65 去掉树上的一个节点, 66 求最大子树结点数的最小值, 67 如果有多个点都是最小值, 68 那么找一个序号最小的节点。 69 输出节点号,和最小值。 70 71 分析: 72 求树的重心模板题, 73 1遍dfs求处每个结点的最大子树结点数, 74 为了使序号最小,则从结点1开始maxt数组找一个最小值. 75 注意这里有多组输入,则每次要初始化链式前向星的etot和head数组. 76 */
B - Boatherds
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 using namespace std; 6 const int amn=1e5+5,inf=1e9; 7 int n,m,K[amn]; 8 9 int head[amn],etot; 10 struct edge{ 11 int nxt,v,w; 12 edge(){} 13 edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){} 14 }eg[amn]; 15 void init(){ 16 etot=0; 17 memset(head,0,sizeof head); 18 } 19 void add(int u,int v,int w){ 20 eg[++etot]=edge(head[u],v,w); 21 head[u]=etot; 22 } 23 24 int siz[amn],maxt[amn],vis[amn],rt; 25 void calsiz(int u,int fa,int sum){ 26 siz[u]=1; 27 maxt[u]=0; 28 for(int i=head[u];i;i=eg[i].nxt){ 29 int v=eg[i].v; 30 if(vis[v]||v==fa)continue; 31 calsiz(v,u,sum); 32 siz[u]+=siz[v]; 33 maxt[u]=max(maxt[u],siz[v]); 34 } 35 maxt[u]=max(maxt[u],sum-siz[u]); 36 if(maxt[u]<maxt[rt])rt=u; 37 } 38 void getroot(int u,int fa,int sum){ 39 rt=0; 40 maxt[rt]=inf; 41 calsiz(u,fa,sum); 42 calsiz(rt,-1,sum); 43 } 44 45 int dis[amn],di[amn],tp; 46 void caldis(int u,int fa){ 47 if(dis[u]>(int)1e7)return; 48 di[++tp]=dis[u]; 49 for(int i=head[u];i;i=eg[i].nxt){ 50 int v=eg[i].v,w=eg[i].w; 51 if(vis[v]||v==fa)continue; 52 dis[v]=dis[u]+w; 53 caldis(v,u); 54 } 55 } 56 57 bool jg[(int)1e7+5]; 58 int ans[amn]; 59 queue<int> bk; 60 void sovle(int u){ 61 jg[0]=1; 62 bk.push(0); 63 for(int i=head[u];i;i=eg[i].nxt){ 64 int v=eg[i].v,w=eg[i].w; 65 if(vis[v])continue; 66 tp=0; 67 dis[v]=w; 68 caldis(v,u); 69 for(int j=1;j<=tp;j++){ 70 for(int k=1;k<=m;k++){ 71 if(K[k]>=di[j])ans[k]+=jg[K[k]-di[j]]; 72 } 73 } 74 for(int j=1;j<=tp;j++){ 75 jg[di[j]]=1; 76 bk.push(di[j]); 77 } 78 } 79 while(bk.size()){ 80 jg[bk.front()]=0; 81 bk.pop(); 82 } 83 } 84 void dfz(int u){ 85 vis[u]=1; 86 sovle(u); 87 for(int i=head[u];i;i=eg[i].nxt){ 88 int v=eg[i].v; 89 if(vis[v])continue; 90 getroot(v,u,siz[v]); 91 dfz(rt); 92 } 93 } 94 int main(){ 95 int a,b; 96 while(~scanf("%d",&n)&&n){ 97 init(); 98 for(int i=1;i<=n;i++){ 99 while(scanf("%d",&a)&&a){ 100 scanf("%d",&b); 101 add(i,a,b); 102 add(a,i,b); 103 } 104 } 105 m=0; 106 while(scanf("%d",&K[++m])&&K[m]); 107 m--; 108 memset(vis,0,sizeof vis); 109 memset(ans,0,sizeof ans); 110 getroot(1,-1,n); 111 dfz(rt); 112 for(int i=1;i<=m;i++){ 113 if(ans[i])printf("AYE "); 114 else printf("NAY "); 115 } 116 puts("."); 117 } 118 } 119 /** 120 题意: 121 求一棵树上是否存在路径长度为K的点对。 122 123 分析: 124 和ppt里的做法一样,只是输入和输出有区别 125 多组输入,注意初始化 126 每个case最后单独一行输出一个'.' 127 */
C - Tree
1 #include<stdio.h> 2 #include<iostream> 3 #include<queue> 4 #include<string.h> 5 #include<algorithm> 6 using namespace std; 7 typedef long long ll; 8 const int amn=2e5+5,inf=2e9,top=2e4+5; 9 10 int n,a,b,c,k; 11 12 int head[amn],etot; 13 struct edge{ 14 int nxt,v,w; 15 edge(){} 16 edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){} 17 }eg[amn]; 18 void add(int u,int v,int w){ 19 eg[++etot]=edge(head[u],v,w); 20 head[u]=etot; 21 } 22 23 int siz[amn],maxt[amn],rt,vis[amn]; 24 void calsiz(int u,int fa,int sum){ 25 siz[u]=1; 26 maxt[u]=0; 27 for(int i=head[u];i;i=eg[i].nxt){ 28 int v=eg[i].v; 29 if(vis[v]||v==fa)continue; 30 calsiz(v,u,sum); 31 siz[u]+=siz[v]; 32 maxt[u]=max(maxt[u],siz[v]); 33 } 34 maxt[u]=max(maxt[u],sum-siz[u]); 35 if(maxt[u]<maxt[rt])rt=u; 36 } 37 void getroot(int u,int fa,int sum){ 38 rt=0; 39 maxt[rt]=inf; 40 calsiz(u,fa,sum); 41 calsiz(rt,-1,sum); 42 } 43 44 int dis[amn],di[amn],tp; 45 void caldis(int u,int fa){ 46 if(dis[u]>k)return ; ///防溢出 47 di[++tp]=dis[u]; 48 for(int i=head[u];i;i=eg[i].nxt){ 49 int v=eg[i].v,w=eg[i].w; 50 if(vis[v]||v==fa)continue; 51 dis[v]=dis[u]+w; 52 caldis(v,u); 53 } 54 } 55 56 int sovle(int u,int fa,int w){ 57 dis[u]=w; 58 tp=0;///记得要初始化栈!!! 59 caldis(u,fa); 60 sort(di+1,di+1+tp); 61 int l=1,r=tp,ans=0; 62 while(l<r){ 63 if(di[l]+di[r]<=k){ 64 ans+=r-l; 65 l++; 66 } 67 else r--; 68 } 69 return ans; 70 } 71 72 int ans; 73 void dfz(int u){ 74 vis[u]=1; 75 ans+=sovle(u,-1,0); 76 for(int i=head[u];i;i=eg[i].nxt){ 77 int v=eg[i].v,w=eg[i].w; 78 if(vis[v])continue; 79 ans-=sovle(v,u,w); 80 getroot(v,u,siz[v]); 81 dfz(rt); 82 } 83 } 84 85 void init(){ 86 etot=0; 87 memset(head,0,sizeof head); 88 ans=0; 89 memset(vis,0,sizeof vis);///每次要初始化标记数组,这个要注意,多组输入的题要拿相同数据多试几遍看输出是否正常 90 } 91 92 int main(){ 93 while(~scanf("%d%d",&n,&k)&&n&&k){ 94 init(); 95 for(int i=1;i<n;i++){ 96 scanf("%d%d%d",&a,&b,&c); 97 add(a,b,c); 98 add(b,a,c); 99 } 100 getroot(1,-1,n); 101 dfz(rt); 102 printf("%d ",ans); 103 } 104 } 105 /** 106 题意: 107 求一棵树上路径长度大于等于1且小于等于K的点对个数。 108 109 分析: 110 和ppt里的做法一样,这里选择双指针法 111 多组输入,注意初始化 112 */
D - D Tree
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 using namespace std; 6 const int amn=5e5+5,inf=2e9,mod=1e6+3; 7 typedef long long ll; 8 9 int n,ansx,ansy; 10 ll V[amn],inv[(int)(mod+5)],K; 11 12 int head[amn],etot; 13 struct edge{ 14 int to,v; 15 edge(){} 16 edge(int to,int v):to(to),v(v){} 17 }eg[amn]; 18 void add(int u,int v){ 19 eg[++etot]=edge(head[u],v); 20 head[u]=etot; 21 } 22 23 int siz[amn],maxt[amn],rt,vis[amn]; 24 void calsiz(int u,int fa,int sum){ 25 siz[u]=1; 26 maxt[u]=0; 27 for(int i=head[u];i;i=eg[i].to){ 28 int v=eg[i].v; 29 if(vis[v]||v==fa)continue; 30 calsiz(v,u,sum); 31 siz[u]+=siz[v]; 32 maxt[u]=max(maxt[u],siz[v]); 33 } 34 maxt[u]=max(maxt[u],sum-siz[u]); 35 if(maxt[u]<maxt[rt])rt=u; 36 } 37 void getroot(int u,int fa,int sum){ 38 rt=0; 39 maxt[rt]=inf; 40 calsiz(u,fa,sum); 41 } 42 43 ll dis[amn],di[amn],tp; 44 void caldis(int u,int fa){ 45 di[++tp]=u; 46 for(int i=head[u];i;i=eg[i].to){ 47 int v=eg[i].v; 48 if(vis[v]||v==fa)continue; 49 dis[v]=V[v]*dis[u]%mod; 50 caldis(v,u); 51 } 52 } 53 54 int tf[(int)(mod+5)]; 55 queue<int> bk; 56 void sovle(int u){ 57 tf[1]=u; 58 bk.push(1); 59 for(int i=head[u];i;i=eg[i].to){ 60 int v=eg[i].v; 61 if(vis[v])continue; 62 tp=0; 63 dis[v]=V[v]; 64 caldis(v,u); 65 for(int j=1;j<=tp;j++){ 66 ll x=di[j],y=tf[K*inv[dis[x]*V[u]%mod]%mod]; 67 if(!y)continue; 68 if(x>y)swap(x,y); 69 if(x<ansx||(x==ansx&&y<ansy)) 70 ansx=x,ansy=y; 71 } 72 for(int j=1;j<=tp;j++){ 73 if(!tf[dis[di[j]]]||di[j]<tf[dis[di[j]]]){ 74 tf[dis[di[j]]]=di[j]; 75 bk.push(dis[di[j]]); 76 } 77 } 78 } 79 while(bk.size()){ 80 tf[bk.front()]=0; 81 bk.pop(); 82 } 83 } 84 85 void dfz(int u){ 86 vis[u]=1; 87 sovle(u); 88 for(int i=head[u];i;i=eg[i].to){ 89 int v=eg[i].v; 90 if(vis[v])continue; 91 getroot(v,u,siz[v]); 92 dfz(rt); 93 } 94 } 95 96 void init(int n){ 97 ansx=ansy=inf; 98 etot=0; 99 memset(head,0,sizeof head); 100 memset(vis,0,sizeof vis); 101 } 102 103 int main(){ 104 inv[1]=1; 105 for(int i=2;i<=mod;i++) 106 inv[i]=(1LL*(-(mod/i)*inv[mod%i]%mod+mod)%mod); 107 while(~scanf("%d%d",&n,&K)){ 108 init(n); 109 for(int i=1;i<=n;i++){ 110 scanf("%lld",&V[i]); 111 } 112 for(int i=1;i<n;i++){ 113 int x,y; 114 scanf("%d%d",&x,&y); 115 add(x,y); 116 add(y,x); 117 } 118 getroot(1,-1,n); 119 dfz(rt); 120 if(ansx==inf)printf("No solution "); 121 else printf("%d %d ",ansx,ansy); 122 } 123 } 124 /** 125 题意: 126 在树上找一条链,使得链上点权值的乘积对1e6+3取模为k,输出两个端点,若有相同情况输出字典序最小的编号. 127 128 分析: 129 130 dis[x]*dis[y]%mod==K 131 | 132 v 133 dis[y]==K*inv[dis[x]]%mod 134 135 用类似判断是否有路径和等于k的方法 136 caldis函数的di数组改为统计端点的编号, 137 solve函数的tf数组改为存端点的编号 138 */
E - 聪聪可可
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int amn=1e5+5,inf=1e9; 5 6 int n,a,b,c; 7 8 int head[amn],egnum; 9 struct edge{ 10 int nxt,v,w; 11 edge(){} 12 edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){} 13 }eg[amn]; 14 void add(int u,int v,int w){ 15 eg[++egnum]=edge(head[u],v,w); 16 head[u]=egnum; 17 } 18 19 int siz[amn],maxt[amn],rt,vis[amn]; 20 void calsiz(int u,int fa,int sum){ 21 siz[u]=1; 22 maxt[u]=0; 23 for(int i=head[u];i;i=eg[i].nxt){ 24 int v=eg[i].v; 25 if(vis[v]||v==fa)continue; 26 calsiz(v,u,sum); 27 siz[u]+=siz[v]; 28 maxt[u]=max(maxt[u],siz[v]); 29 } 30 maxt[u]=max(maxt[u],sum-siz[u]); 31 if(maxt[u]<maxt[rt])rt=u; 32 } 33 void getroot(int u,int fa,int sum){ 34 rt=0; 35 maxt[rt]=inf; 36 calsiz(u,fa,sum); 37 calsiz(rt,-1,sum); 38 } 39 40 int dis[amn],di[amn],tp; 41 void caldis(int u,int fa){ 42 di[++tp]=dis[u]; 43 for(int i=head[u];i;i=eg[i].nxt){ 44 int v=eg[i].v,w=eg[i].w; 45 if(vis[v]||v==fa)continue; 46 dis[v]=dis[u]+w; 47 caldis(v,u); 48 } 49 } 50 51 int jg[5],ans; 52 void solve(int u){ 53 for(int i=head[u];i;i=eg[i].nxt){ 54 int v=eg[i].v,w=eg[i].w; 55 if(vis[v])continue; 56 tp=0; 57 dis[v]=w; 58 caldis(v,u); 59 for(int j=1;j<=tp;j++){ 60 ans+=2*((di[j]%3==0?1:0)+jg[(3-di[j]%3+3)%3]); 61 } 62 for(int j=1;j<=tp;j++){ 63 jg[di[j]%3]++; 64 } 65 } 66 jg[0]=jg[1]=jg[2]=0; 67 } 68 void dfz(int u){ 69 vis[u]=1; 70 solve(u); 71 for(int i=head[u];i;i=eg[i].nxt){ 72 int v=eg[i].v,w=eg[i].w; 73 if(vis[v])continue; 74 getroot(v,u,siz[v]); 75 dfz(rt); 76 } 77 } 78 79 int gcd(int a,int b){ 80 return b?gcd(b,a%b):a; 81 } 82 83 int main(){ 84 scanf("%d",&n); 85 for(int i=1;i<n;i++){ 86 scanf("%d%d%d",&a,&b,&c); 87 add(a,b,c); 88 add(b,a,c); 89 } 90 ans=n; 91 getroot(1,-1,n); 92 dfz(rt); 93 int fm=n*n; 94 int g=gcd(ans,fm); 95 printf("%d/%d ",ans/g,fm/g); 96 } 97 /** 98 题意: 99 给一颗树,有n给点,两个点之间所有边上数的和加起来恰好是3的倍数的概率,用最简分数形式输出 100 101 分析: 102 求出两个点之间所有边上数的和加起来恰好是3的倍数的数量,和所有路径数n*n求gcd即可 103 所以问题是如何求路径距离为3的倍数的数量 104 如果一个数a是3的倍数,则a%3==0 105 如果数b和c不是3的倍数,则b%3==1,c%3==2 106 那么3的倍数有下列情况:a%3==0,(a+a)%3==0,(b+c)%3==0 107 按照求路径距离为k的个数的方法改下sovle函数就行了 108 注意这里是有向路径,而我们只算了一个方向,所以中累加答案时要乘2 109 */
F - Garden of Eden
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 typedef long long ll; 6 const int amn=1e5+5,inf=2e9; 7 8 int n,k; 9 ll ans; 10 11 int head[amn],egnum,type[amn]; 12 struct edge{ 13 int to,v; 14 edge(){} 15 edge(int to,int v):to(to),v(v){} 16 }eg[amn]; 17 void add(int u,int v){ 18 eg[++egnum]=edge(head[u],v); 19 head[u]=egnum; 20 } 21 void add_eg(int u,int v){ 22 add(u,v); 23 add(v,u); 24 } 25 26 int siz[amn],maxt[amn],rt;bool vis[amn]; 27 void calsiz(int u,int fa,int sum){ 28 siz[u]=1; 29 maxt[u]=0; 30 for(int i=head[u];i;i=eg[i].to){ 31 int v=eg[i].v; 32 if(v==fa||vis[v])continue; 33 calsiz(v,u,sum); 34 siz[u]+=siz[v]; 35 maxt[u]=max(maxt[u],siz[v]); 36 } 37 maxt[u]=max(maxt[u],sum-siz[u]); 38 if(maxt[u]<maxt[rt])rt=u; 39 } 40 void getroot(int u,int fa,int sum){ 41 rt=0; 42 maxt[rt]=inf; 43 calsiz(u,fa,sum); 44 } 45 46 ll di[amn],tp,cnt; 47 void caldis(int u,int fa,ll cnt){ 48 di[++tp]=cnt; 49 for(int i=head[u];i;i=eg[i].to){ 50 int v=eg[i].v; 51 if(v==fa||vis[v])continue; 52 caldis(v,u,cnt|(1<<(type[v]-1))); 53 } 54 } 55 ll tf[3000]; 56 ll tot; 57 ll sovle(int u,int fa){ 58 ll an=0; 59 tp=0; 60 caldis(u,fa,(1<<(type[u]-1))|(1<<(type[fa]-1))); 61 for(int i=1;i<=tp;i++)tf[di[i]]++; ///处理了所有路径情况 62 for(int i=1;i<=tp;i++){ 63 tf[di[i]]--; ///这里是当前路径与其他路径组合,所以要减掉自身 64 an+=tf[tot]; 65 for(int j=di[i];j;j=((j-1)&di[i]))an+=tf[tot^j]; ///枚举di[i]状态的子集 66 tf[di[i]]++; ///还原自身 67 } 68 for(int i=1;i<=tp;i++){ 69 tf[di[i]]=0; 70 } 71 return an; 72 } 73 void dfz(int u){ 74 vis[u]=1; 75 ans+=sovle(u,u); 76 for(int i=head[u];i;i=eg[i].to){ 77 int v=eg[i].v; 78 if(vis[v])continue; 79 ans-=sovle(v,u); ///sovle函数算了rt结点,所以要减掉不合法的情况,详情见ppt双指针的内容 80 getroot(v,u,siz[v]); 81 dfz(rt); 82 } 83 } 84 void init(int n){ 85 ans=egnum=0; 86 for(int i=1;i<=n;i++)head[i]=vis[i]=0; 87 tot=(1<<k)-1; 88 } 89 90 int main(){ 91 while(~scanf("%d%d",&n,&k)){ 92 init(n); 93 for(int i=1;i<=n;i++){ 94 scanf("%d",&type[i]); 95 } 96 int u,v; 97 for(int i=1;i<n;i++){ 98 99 scanf("%d%d",&u,&v); 100 add_eg(u,v); 101 } 102 if(k==1){printf("%d ",n*n);continue;} 103 getroot(1,-1,n); 104 dfz(rt); 105 printf("%lld ",ans); 106 } 107 } 108 /** 109 题意: 110 给一棵树,树上有K种苹果, 111 问从任意点出发,到任意点结束, 112 把路径上的所有苹果种类取全, 113 能够取全K种苹果的有向点对数(1->2和2->1是不同的) 114 115 分析: 116 我们需要记录每个点到根节点的路径上取到的苹果的种类 117 再看这条路径是否把苹果种类取全, 118 或它能与其他子树的哪些路径互补使得这条组合路径把苹果种类取全 119 注意,如果一条路径把苹果取全后,那么它能与任意其他子树的哪些路径互补使得这条组合路径把苹果种类取全 120 因为它本来就是种类齐全的 121 如果用二进制表示,就像这样( | 是或运算):1111 | 0001 = 1111, 1111 | 0011 = 1111, 122 这就启发了我们使用二进制来表示路径取苹果种类的状态, 123 每条路径状态都可以与全1状态互补为全1状态,每条路径算答案时都要加上当前全1状态路径数 124 125 我们知道,^是异或运算,a^b==c , b==c^a ,也就是说,已知c和a就可以通过异或求出b, 126 这就启发了我们用异或来查询其他子树的路径状态数 127 128 由前面分析的种类齐全的情况, 129 启发了我们如果得到一个路径状态a, 130 那么a的子集也由可能与其他子树的路径互补为全1状态 131 */
G - Distance Statistics
1 #include<stdio.h> 2 #include<iostream> 3 #include<queue> 4 #include<string.h> 5 #include<algorithm> 6 using namespace std; 7 typedef long long ll; 8 const int amn=2e5+5,inf=2e9,top=2e4+5; 9 10 int n,m,a,b,c,k; 11 12 int head[amn],etot; 13 struct edge{ 14 int nxt,v,w; 15 edge(){} 16 edge(int nxt,int v,int w):nxt(nxt),v(v),w(w){} 17 }eg[amn]; 18 void add(int u,int v,int w){ 19 eg[++etot]=edge(head[u],v,w); 20 head[u]=etot; 21 } 22 23 int siz[amn],maxt[amn],rt,vis[amn]; 24 void calsiz(int u,int fa,int sum){ 25 siz[u]=1; 26 maxt[u]=0; 27 for(int i=head[u];i;i=eg[i].nxt){ 28 int v=eg[i].v; 29 if(vis[v]||v==fa)continue; 30 calsiz(v,u,sum); 31 siz[u]+=siz[v]; 32 maxt[u]=max(maxt[u],siz[v]); 33 } 34 maxt[u]=max(maxt[u],sum-siz[u]); 35 if(maxt[u]<maxt[rt])rt=u; 36 } 37 void getroot(int u,int fa,int sum){ 38 rt=0; 39 maxt[rt]=inf; 40 calsiz(u,fa,sum); 41 calsiz(rt,-1,sum); 42 } 43 44 int dis[amn],di[amn],tp; 45 void caldis(int u,int fa){ 46 if(dis[u]>k)return ; ///防溢出 47 di[++tp]=dis[u]; 48 for(int i=head[u];i;i=eg[i].nxt){ 49 int v=eg[i].v,w=eg[i].w; 50 if(vis[v]||v==fa)continue; 51 dis[v]=dis[u]+w; 52 caldis(v,u); 53 } 54 } 55 56 int sovle(int u,int fa,int w){ 57 dis[u]=w; 58 tp=0;///记得要初始化栈!!! 59 caldis(u,fa); 60 sort(di+1,di+1+tp); 61 int l=1,r=tp,ans=0; 62 while(l<r){ 63 if(di[l]+di[r]<=k){ 64 ans+=r-l; 65 l++; 66 } 67 else r--; 68 } 69 return ans; 70 } 71 72 int ans; 73 void dfz(int u){ 74 vis[u]=1; 75 ans+=sovle(u,-1,0); 76 for(int i=head[u];i;i=eg[i].nxt){ 77 int v=eg[i].v,w=eg[i].w; 78 if(vis[v])continue; 79 ans-=sovle(v,u,w); 80 getroot(v,u,siz[v]); 81 dfz(rt); 82 } 83 } 84 85 void init(){ 86 etot=0; 87 memset(head,0,sizeof head); 88 ans=0; 89 memset(vis,0,sizeof vis);///每次要初始化标记数组,这个要注意,多组输入的题要拿相同数据多试几遍看输出是否正常 90 } 91 92 int main(){ 93 char in; 94 while(~scanf("%d%d",&n,&m)){ 95 init(); 96 for(int i=1;i<=m;i++){ 97 scanf("%d%d%d %c",&a,&b,&c,&in); 98 add(a,b,c); 99 add(b,a,c); 100 } 101 scanf("%d",&k); 102 getroot(1,-1,n); 103 dfz(rt); 104 printf("%d ",ans); 105 } 106 } 107 /** 108 题意: 109 求一棵树上路径长度大于等于1且小于等于K的点对个数。 110 111 分析: 112 和ppt里的做法一样,这里选择双指针法 113 多组输入,注意初始化 114 和poj1741不同的是K (1 <= K <= 1,000,000,000)变为最大到1e9了,输入也有不同 115 */