• poj1741(入门点分治)


    题目链接:https://vjudge.net/problem/POJ-1741

    题意:给出一棵树,求出树上距离不超过k的点对数量。

    思路:点分治经典题。先找重心作为树根,然后求出子树中所有点到重心的距离dis[i],那么所有组合为dis[i]+dis[j]<=k,其中不合法组合为在重心的同一个子树内的情况,所以要减去在重心的子树中仍满足dis[i]+dis[j]<=k的情况。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int inf=0x3f3f3f3f;
    const int maxn=10005;
    struct node1{
        int v,w,nex;
    }edge[maxn<<1];
    
    struct node2{
        int x,y;
    }arr[maxn];
    
    int n,k,cnt,ans,head[maxn],sz[maxn],mson[maxn],Min,root,size;
    int vis[maxn],t,tt,dis[maxn],pre[maxn];
    
    void adde(int u,int v,int w){
        edge[++cnt].v=v;
        edge[cnt].w=w;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    
    void getroot(int u,int fa){
        sz[u]=1,mson[u]=0;
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]||v==fa) continue;
            getroot(v,u);
            sz[u]+=sz[v];
            if(sz[v]>mson[u]) mson[u]=sz[v];
        }
        if(size-sz[u]>mson[u]) mson[u]=size-sz[u];
        if(mson[u]<Min) Min=mson[u],root=u;
    }
    
    void getdis(int u,int fa,int len){
        dis[++t]=len;
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]||v==fa) continue;
            getdis(v,u,len+edge[i].w);
        }
    }
    
    void solve(int x,int y,int f){
        t=0;
        getdis(x,0,y);
        sort(dis+1,dis+t+1);
        tt=0,dis[0]=-1,pre[0]=0;
        for(int i=1;i<=t;++i)
            if(dis[i]!=dis[i-1]) arr[++tt].x=dis[i],arr[tt].y=1,pre[tt]=pre[tt-1]+1;
            else ++arr[tt].y,++pre[tt];
        for(int i=1;i<=tt&&arr[i].x<=k/2;++i)
            ans+=(arr[i].y-1)*arr[i].y/2*f;
        for(int i=1;i<=tt&&arr[i].x<k/2;++i){
            int l=i+1,r=tt,mid;
            while(l<=r){
                mid=(l+r)>>1;
                if(arr[i].x+arr[mid].x<=k) l=mid+1;
                else r=mid-1;
            }
            ans+=(arr[i].y)*(pre[r]-pre[i])*f;
        }
    }
    
    void fenzhi(int u,int ssize){
        vis[u]=1;
        solve(u,0,1);
        for(int i=head[u];i;i=edge[i].nex){
            int v=edge[i].v;
            if(vis[v]) continue;
            solve(v,edge[i].w,-1);
            Min=inf,root=0;
            size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]);
            getroot(v,0);
            fenzhi(root,size);
        }
    }
    
    int main(){
        while(scanf("%d%d",&n,&k),n||k){
            cnt=ans=0;
            for(int i=0;i<=n;++i)
                head[i]=0,vis[i]=0;
            for(int i=1;i<n;++i){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                adde(u,v,w);
                adde(v,u,w);
            }
            Min=inf,root=0,size=n;
            getroot(1,0);
            fenzhi(root,n);
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    mysql数据库查询库中所有表所占空间大小
    mysql行转列
    mysql重置密码
    POJ1426 Find The Multiple —— BFS
    POJ3279 Fliptile —— 状态压缩 + 模拟
    POJ1077 Eight —— IDA*算法
    POJ1077 Eight —— A*算法
    POJ1077 Eight —— 双向BFS
    POJ1077 Eight —— 反向BFS
    POJ1077 Eight —— 正向BFS
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11382097.html
Copyright © 2020-2023  润新知