点分治
用于求解树上长度为k的路径的数量问题
主要就是**找树的重心+容斥思想**
以下是一些题目:
luoguP3806
模板题
求树上长度为k的路径是否存在问题
#include<stdio.h> #include<algorithm> #include<iostream> using namespace std; const int maxn=1e4+5; const int inf=0x3f3f3f3f; struct edge{ int v, next; int w; }e[maxn*2]; int head[maxn]; int total=0; void addedge(int u, int v, int w){ total++; e[total].v=v; e[total].w=w; e[total].next=head[u]; head[u]=total; } int sim[maxn];//size of the tree i int mxson[maxn]; int root; int MX=0; int Smer; bool vis[maxn]; void getroot(int u,int fa) { sim[u] = 1; mxson[u] = 0; for(int i = head[u];i;i = e[i].next) { int v = e[i].v; if(vis[v]||v == fa)continue; getroot(v,u); sim[u] = sim[u] + sim[v]; mxson[u] = max(mxson[u],sim[v]); } mxson[u] = max(mxson[u],Smer - sim[u]); if(mxson[u]<MX){ root = u; MX = mxson[u]; } } int dist[maxn]; int ans[10000005]; void query(int& cnt, int u, int fa, int len){//以u为根,树上节点到u的长度 dist[++cnt]=len; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(vis[v]||v==fa)continue; query(cnt, v, u, e[i].w+len); } } void solve(int u, int len, int key){ int cnt=0; query(cnt, u, 0, len); if(key){ for(int i=1;i<cnt;i++){ for(int j=i+1;j<=cnt;j++){ ans[dist[i]+dist[j]]++; } } }else{ for(int i=1;i<cnt;i++){ for(int j=i+1;j<=cnt;j++){ ans[dist[i]+dist[j]]--; } } } } void Divide(int u) { solve(u, 0, 1);//算上所有的 vis[u] = true; for(int i = head[u];i;i = e[i].next) { int v = e[i].v; if(vis[v])continue; solve(v,e[i].w, 0);//减去相同链的 Smer = sim[v]; root = 0;MX = inf; getroot(v,0);//get subtree's root Divide(root); } return; } int main() { freopen("in.txt","r",stdin); int n,m; scanf("%d%d",&n,&m); int cnt=n-1; while(cnt--){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } MX=inf; Smer=n; getroot(1, 0); Divide(root); while(m--){ int k; scanf("%d",&k); if(ans[k])printf("AYE\n"); else printf("NAY\n"); } }
poj1741
求树上小于等于k的路径数
套用板子就行
solve那里需要优化:dist从小排到大,用二分求解出符合的路径数
while(left<=right){ if(dist[left]+dist[right]<=k){ temp+=right-left; left++; }else{ right--; } }
luoguP2634
余2和余1的合起来*2+余0和余0的合起来
这样余数运算就只有n次,不是n^2次,不会tle
这题也能用树上dp写

浙公网安备 33010602011771号