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的每个儿子在进行相同的步骤(就是分治嘛~)

点剖の实现

首先我们要解决第一个问题,如何找根?对于一颗子树,如果随意找一个根,那么对于一条链的情况时间复杂度显然会增加到n2logn那么我们怎么找一个根,使得速度最快呢?因为是分治,那么当一个根所有子树中最大的子树最小的时候耗时是最短的。那么这个根就是当前这棵树的重心啦。

在找到重心之后,我们用一个dfs求出上述的dis数组。那么我们怎么在O(dis数组中数的个数)的时间内求出有多少对dis[i]+dis[j](i不等于j)小于等于k呢?
我们可以先把dis数组从小到大排序,先确定左端点i,如果有一个dis[i]+dis[j]<=k(i<j)那么dis[i]+dis[i+1到j-1]这一段都是小于等于k的,而且在i往右边移动的情况下,j是不会往右边移动的,只会往左边移动或者不动,那么从左到右枚举一个i就可以了,j最多移动与i同样的次数。

那么我们就先以当前重心为根做一遍,把答案加到ans里,在以root的每一个孩子为根做一次,然后在用ans减去这些答案就好了(以root孩子为根再做一遍的时候要注意dis[i]表示的是节点i到节点root的距离,而不是root的孩子的距离)

时间复杂度的分析:我们知道如果以一颗树的重心作为这颗树的根,那么每一棵子树的大小都不超过n/2。那么我们递归的深度就是logn,对于每一个递归中的状态,我们需要nlogn的时间解决问题。所以最后的时间复杂度应该是nlog2n

贴代码

感受下这丑陋到恐怖的代码的威力吧啊哈哈哈哈哈哈哈哈

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.
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 酷派手机的信息文件夹不见了怎么办 酷派手机开机卡在开机界面怎么办 魅蓝拨号键老是闪退怎么办 手机上浏览器搜索时字在右边怎么办 酷比魔方平板开不开机怎么办 红米手机摔了有一角黑屏了怎么办 红米手机刷机黑屏打不开怎么办 魅蓝x一打电话就黑屏怎么办 红米手机黑屏打不开怎么办充电发烫 小米手机打电话来是关机的怎么办 红米手机打电话自动灭屏怎么办 红米5s手机白屏怎么办 红米手机黑屏开不了机怎么办 红米note开机键不灵了怎么办 红米2忘记锁屏密码怎么办 红米1手机忘记锁屏密码怎么办 红米4x关不了机怎么办 红米4a手机屏幕黑屏打不开怎么办 红米手机为什么开不了机怎么办 红米note手机刷机失败怎么办 金立手机来电屏幕不亮怎么办 小米5s桌面相机图标不见了怎么办 小米手机锁屏密码忘了怎么办? 小米平板电脑锁屏密码忘了怎么办 小米手机进水了黑屏了嗡嗡响怎么办 华为诺娃2手机声音小怎么办 华为平板锁屏密码忘记了怎么办 华为麦芒6手机按键摔坏了怎么办 定频空调加错了佛里昂怎么办 定频空调外机噪音大怎么办 老美的定频空调出现p0怎么办 华为揽阅m2青春版卡顿了怎么办 华为揽阅M2青春版发热卡顿怎么办 全民突击网速不给力经常掉线怎么办 华为手机微信视频黑屏了怎么办 相机拍照后找不到拍的照片怎么办 苹果手机下载软件不被信任怎么办 苹果x手机下载软件不受信任怎么办 华为畅享7plus主板坏了怎么办 华为手机手机主板坏了没备份怎么办 华为手机一年内主板坏了怎么办