poj1741 tree 点分治

来源:互联网 发布:mac压缩包怎么解压 编辑:程序博客网 时间:2024/04/29 23:26

把这几天写的东西上传一下
写博客的意义大概就是整理一下思路 以及方便日后复习
不得不说 把代码放在文件夹里
做完我是不会过目的
写博客 或许会增加我的成就感
从而 会多注意一下吧
哈哈 csdn现在也高大上了很多嘛
poj1741 Tree
题目大意:求(u,v)满足dis(u,v)<=k的点对数 N<=10000
点分治 LNWC2016新学到的 Orz
大概是 把所有的边分为经过点 x (重心) 和不经过点x
不经过点x的 多棵子树递归处理
可以证明递归次数不超过 logN 次
刚学完时候想尝试徒手写失败了= =
参考了hzwer的点分治= =
在这里%%%
但是我发现了个问题 点分治每次找的不是重心 但黄学长说没影响 不知道为什么
此题题解:
对于每次处理的根节点
求出它的子树所有点到距离 排序
ans+= dis(u,root)+dis(root,v)<=k 的点对数
但对于(u,v)在一棵子树上的情况 本不应该算入
所以答案还要减去(u,v)在一棵子树的情况

这个点分治是模仿hzwer实现的 有时间再写一发这题或别的题QAQ
在这里立个flag呦

#include<iostream>#include<cstdio> #include<algorithm>using namespace std;const int N=10010;const int inf=0x7fffffff;struct E {int to,nxt,val;}edge[N*2];int idx[N],can[N],size[N],deep[N],d[N],f[N];int tot,root,ans,ret,sum,p;int n,k;void init(){    tot=1;root=0;ans=0;sum=n;    fill(idx,idx+N,0);    fill(can,can+N,1);    fill(size,size+N,0);    fill(deep,deep+N,0);    fill(d,d+N,0);    fill(f,f+N,0);f[0]=inf;}void addedge(int from,int to,int val){    edge[tot].to=to;edge[tot].val=val;edge[tot].nxt=idx[from];idx[from]=tot++;}void getroot(int x,int fa){    size[x]=1;f[x]=0;    for(int t=idx[x];t;t=edge[t].nxt){        E e=edge[t];        if(can[e.to] && e.to!=fa){            getroot(e.to,x);            f[x]=max(f[x],size[e.to]);            size[x]+=size[e.to];        }    }    f[x]=max(f[x],sum-size[x]);    if(f[x]<f[root]) root=x;}void getdeep(int x,int fa){    deep[++p]=d[x];    for(int t=idx[x];t;t=edge[t].nxt){        E e=edge[t];        if(can[e.to] && e.to!=fa) {            d[e.to]=d[x]+e.val;            getdeep(e.to,x);        }    }}int calc(int x,int now){    ret=0;d[x]=now;p=0;    getdeep(x,0);    sort(deep+1,deep+1+p);    int r=p;    for(int l=1;l<=p;l++){        while(deep[l]+deep[r]>k) r--;        if(r<=l) break;        ret+=(r-l);    }    return ret;}void work(int x){    ans+=calc(x,0);    can[x]=0;    for(int t=idx[x];t;t=edge[t].nxt){        E e=edge[t];        if(can[e.to]){            sum=size[e.to];            ans-=calc(e.to,e.val);            root=0;            getroot(e.to,0);            work(root);        }    }}int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    while(1){        scanf("%d%d",&n,&k);        if(n==0 && k==0) break;        init();        for(int i=1;i<n;i++){            int x,y,w;            scanf("%d%d%d",&x,&y,&w);            addedge(x,y,w);addedge(y,x,w);        }        getroot(1,0);        work(root);        printf("%d\n",ans);    }    return 0;} 
0 0
原创粉丝点击