POJ 1741 点分治(点剖)の学习以及模板
来源:互联网 发布:纸模型软件 编辑:程序博客网 时间:2024/05/02 00:00
发现其实在学习新算法的时候自己先打一下,再看一看标最好。不然可能有很多漏洞2333
点剖の思想
点剖其实就是一个基于树上的分治算法,点剖模板解决了一个快速求树上有多少条边长度<=k的问题,假设我们已经确定了一颗树的根,那么在当前树上长度<=k的边有下列两种情况:
1:这一条边经过根
2:这一条边不经过根
对于第二种情况,我们只需要进行递归求解就可以了(如果一直递归下去总有一次这条边会经过根的)
我们可以设一个dis[i]表示节点i到根节点的距离
再定义parent[i]; parent[root]=-1,如果当前节点的父亲节点为root,那么parent[i]=i,除去上述两种情况,parent[i]=parent[fa[i]](fa[i]表示i节点的父亲)
对于第一种情况,如果有一个dis[i]+dis[j]<=k,那么答案就可以加一。
但是如果parent[i]=parent[j]相等呢?那么这条边不经过根,但是却又被统计到答案里面了,所以我们要减去这一部分的情况。
然后再对root的每个儿子在进行相同的步骤(就是分治嘛~)
点剖の实现
首先我们要解决第一个问题,如何找根?对于一颗子树,如果随意找一个根,那么对于一条链的情况时间复杂度显然会增加到
在找到重心之后,我们用一个dfs求出上述的dis数组。那么我们怎么在O(dis数组中数的个数)的时间内求出有多少对dis[i]+dis[j](i不等于j)小于等于k呢?
我们可以先把dis数组从小到大排序,先确定左端点i,如果有一个dis[i]+dis[j]<=k(i
那么我们就先以当前重心为根做一遍,把答案加到ans里,在以root的每一个孩子为根做一次,然后在用ans减去这些答案就好了(以root孩子为根再做一遍的时候要注意dis[i]表示的是节点i到节点root的距离,而不是root的孩子的距离)
时间复杂度的分析:我们知道如果以一颗树的重心作为这颗树的根,那么每一棵子树的大小都不超过n/2。那么我们递归的深度就是
贴代码
感受下这丑陋到恐怖的代码的威力吧啊哈哈哈哈哈哈哈哈
var size,maxt,dis,vis:array[0..100005]of longint; a:array[0..100005,1..3]of longint; b:array[0..100005,1..2]of longint; i,j,k,l,n,t,x,y,z,m,ans,root,max:longint;procedure qsort(l,r:longint);var i,j,mid:longint;begin i:=l; j:=r; mid:=a[(i+j) div 2,1]; repeat while a[i,1]<mid do inc(i); while a[j,1]>mid do dec(j); if i<=j then begin a[0]:=a[i]; a[i]:=a[j]; a[j]:=a[0]; inc(i); dec(j); end; until i>j; if i<r then qsort(i,r); if l<j then qsort(l,j);end;procedure sort_dis(l,r:longint);var i,j,mid,tmp:longint;begin i:=l; j:=r; mid:=dis[(i+j) div 2]; repeat while dis[i]<mid do inc(i); while dis[j]>mid do dec(j); if i<=j then begin tmp:=dis[i]; dis[i]:=dis[j]; dis[j]:=tmp; inc(i); dec(j); end; until i>j; if i<r then sort_dis(i,r); if l<j then sort_dis(l,j);end;procedure star;begin b[a[1,1],1]:=1; for i:=2 to m do if a[i,1]<>a[i-1,1] then begin b[a[i-1,1],2]:=i-1; b[a[i,1],1]:=i; end; b[a[m,1],2]:=m; a[0,1]:=0; a[0,2]:=0; a[0,3]:=0;end;procedure dfssize(x,p:longint);var i,v:longint;begin size[x]:=1; maxt[x]:=0; for i:=b[x,1] to b[x,2] do begin if (a[i,2]=p) or (vis[a[i,2]]>0) then continue; v:=a[i,2]; dfssize(v,x); size[x]:=size[x]+size[v]; if size[v]>maxt[x] then maxt[x]:=size[v]; end;end;procedure dfsroot(r,x,p:longint);var i:longint;begin if size[r]-size[x]>maxt[x] then maxt[x]:=size[r]-size[x]; if maxt[x]<max then begin max:=maxt[x]; root:=x; end; for i:=b[x,1] to b[x,2] do begin if (a[i,2]=p) or (vis[a[i,2]]>0) then continue; dfsroot(r,a[i,2],x); end;end;procedure dfsdis(x,v,p:longint);var i,z:longint;begin inc(dis[0]); dis[dis[0]]:=v; for i:=b[x,1] to b[x,2] do begin z:=a[i,2]; if (z<>p) and (vis[z]=0) then dfsdis(z,v+a[i,3],x); end;end;function calc(x,p:longint):longint;var i,j:longint;begin dis[0]:=0; dfsdis(x,p,0); sort_dis(1,dis[0]); i:=1; j:=dis[0]; calc:=0; while i<j do begin while (dis[i]+dis[j]>k) and (i<j) do dec(j); calc:=calc+j-i; inc(i); end; exit(calc);end;procedure dfs(x:longint);var i:longint;begin dfssize(x,0); max:=maxlongint; dfsroot(x,x,0); ans:=ans+calc(root,0); vis[root]:=1; for i:=b[root,1] to b[root,2] do begin if vis[a[i,2]]<>0 then continue; ans:=ans-calc(a[i,2],a[i,3]); dfs(a[i,2]); end;end;procedure init;begin readln(m,k); dec(m); if (k=0) or (m=0) then halt; for i:=1 to m do begin readln(a[i,1],a[i,2],a[i,3]); a[m+i,1]:=a[i,2]; a[m+i,2]:=a[i,1]; a[m+i,3]:=a[i,3]; end; m:=m*2; qsort(1,m); star; ans:=0; fillchar(vis,sizeof(vis),0); vis[0]:=1;end;begin //assign(input,'dian_fen_zhi.in'); reset(input); while true do begin init; dfs(1); writeln(ans); end; // close(input);end.
- POJ 1741 点分治(点剖)の学习以及模板
- POJ-1741 (点分治模板)
- 树分治(点分治模板)poj-1741 Tree
- 树分治(点分治模板)poj-1741 Tree
- 树分治(点分治模板)poj-1741 Tree
- poj 1741 洛谷 3806 【模板】点分治1 树的分治 点分治
- poj 1741 洛谷 3806 【模板】点分治1 树的分治 点分治
- POJ 1741 点分治
- 【poj 1741】点分治
- POJ-1741 点分治
- POJ 1741 点分治
- poj 1741 点分治
- poj 1741 点分治
- poj 1741 (点分治入门)
- poj-1741(树分治 点权)
- POJ 1741 Tree(点分治)
- POJ 1741 Tree(树+点分治)
- 【POJ 1741】Tree (树上点分治)
- grpc java helloworld 简单demo实现
- Git版本恢复命令reset
- stub 和 skeleton 的简单实现
- Android替换/修改系统默认输入法
- 前端静态资源版本更新与缓存之——通过gulp 在原html文件上自动化添加js、css版本号
- POJ 1741 点分治(点剖)の学习以及模板
- poj2349
- POJ 3484(规律+二分)
- Go中的素数筛选
- 任务的隔离和特权级保护
- js中parseInt();random();Math.ceil的学习
- 设计模式实现——创建者模式
- c++和java区别之string字符串
- 32位保护模式学习小结(3)---任务切换