传送门
文章目录
- 题意:
- 思路:
题意:
思路:
好久没写淀粉质了,心血来潮复习一下。
淀粉质通常用来统计路径个数,将路径分为子树内的和子树之间的。子树内的递归处理,子树间的存下信息来每次都处理即可,注意不要漏掉子树到根节点的贡献。
这个题要求不超过kkk的路径有多少条,我们一个很容易想到的思路就是将每个子树到伪重心的距离都存下来,每次与前面存下来的子树信息算一下答案。
这个实现起来复杂度很高,每次计算答案需要遍历之前的子树,这样就每一层的复杂度是O(n2)O(n^2)O(n2)级别的了,显然不能接受。当然你可以使用一些黑科技维护一下,但是没必要,我们有更好的算法。
考虑一个容斥,如果将所有路径都存下来,排个序之后二分找答案,这样算出来的答案可以发现不仅有两个子树之间的,还有子树内部的,所以我们在每次遍历完一个子树的时候将答案减去即可。
由于每一层需要排序,复杂度O(nlognlogn)O(nlognlogn)O(nlognlogn)。
// Problem: 树
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/254/
// Memory Limit: 10 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=10010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,k;
vector<PII>v[N];
vector<int>q,qt;
bool st[N];int get_size(int u,int f) {if(st[u]) return 0;int ans=1;for(auto x:v[u]) if(x.X!=f) {ans+=get_size(x.X,u);}return ans;
}int get_wc(int u,int f,int tot,int &wc) {if(st[u]) return 0;int sum=1,mx=0;for(auto x:v[u]) {if(x.X==f) continue;int now=get_wc(x.X,u,tot,wc);mx=max(mx,now); sum+=now;}mx=max(mx,tot-sum);if(mx<=tot/2) wc=u;return sum;
}void get_dis(int u,int f,int w) {if(st[u]) return;q.pb(w);for(auto x:v[u]) {if(x.X==f) continue;get_dis(x.X,u,w+x.Y);}
}LL calc(int u) {if(st[u]) return 0;get_wc(u,-1,get_size(u,-1),u);LL ans=0; st[u]=true;for(auto x:v[u]) {get_dis(x.X,-1,x.Y);sort(q.begin(),q.end());for(int i=0;i<q.size();i++) {int pos=upper_bound(q.begin(),q.end(),k-q[i])-q.begin();ans-=min(pos,i+1);qt.pb(q[i]); ans+=q[i]<=k;}q.clear();}sort(qt.begin(),qt.end());for(int i=0;i<qt.size();i++) {int pos=upper_bound(qt.begin(),qt.end(),k-qt[i])-qt.begin(); ans+=min(pos,i+1);}qt.clear();for(auto x:v[u]) ans+=calc(x.X);return ans;
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);while(scanf("%d%d",&n,&k)&&(n+k)) {for(int i=1;i<=n-1;i++) {int a,b,w; scanf("%d%d%d",&a,&b,&w);v[a].pb({b,w}); v[b].pb({a,w});} printf("%lld\n",calc(0));for(int i=0;i<n;i++) v[i].clear(),st[i]=0;}return 0;
}
/**/