zoukankan      html  css  js  c++  java
  • Tree POJ

    题意:

    给出一棵n个点的树,带权值,问两点之间简单路径长度 (leq k) 的点对的个数。

    分析:

    点分治。

    代码【模板】:

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    #include <string>
    #define pb push_back
    using namespace std;
    typedef pair<int,int>P;
    typedef long long ll;
    const int N=1e4+5;
    struct edge
    {
        int to,nxt,len;
    }G[N<<1];
    int head[N],cot;
    int dis[N],sz[N],focus,minn;
    bool vis[N];//防止一个点重复找
    int k,tn;//
    ll ans;
    void init()
    {
        memset(head,-1,sizeof(head));
        cot=1;
    }
    void addedge(int from,int to,int len)
    {
        G[cot].to=to;
        G[cot].len=len;
        G[cot].nxt=head[from];
        head[from]=cot++;
    }
    void read(int &x)
    {
        x=0;
        int f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    void dfs(int v,int p)//找重心v:根,p:父亲,
    {
        sz[v]=1;
        int res=0;//最大子树的大小
        for(int i=head[v];i!=-1;i=G[i].nxt)
        {
            int u=G[i].to;
            if(u==p||vis[u])
                continue;
            dfs(u,v);
            sz[v]+=sz[u];
            res=max(res,sz[u]);
        }
        res=max(res,tn-sz[v]);//另外一棵子树
        if(res<minn)
        {
            minn=res;
            focus=v;
        }
    }
    void dfs2(int v,int p,int &cnt,int d)//求当前子树中各点离根的距离
    {
        dis[++cnt]=d;
        for(int i=head[v];i!=-1;i=G[i].nxt)
        {
            int t=G[i].to;
            if(t==p||vis[t])
                continue;
            dfs2(t,v,cnt,d+G[i].len);
        }
    }
    int solve(int v,int d)//以重心为根进行处理
    {
        if(k<2*d)
            return 0;
        int cnt=0,res=0;
        dfs2(v,v,cnt,0);//处理出子树中各点到根的距离
        sort(dis+1,dis+1+cnt);
        int l=1,r=cnt;
        while(l<=r)//类似二分,计数
        {
            if(dis[l]+dis[r]<=k-2*d)
            {
                res+=(r-l);
                l++;
            }
            else
                r--;
        }
        return res;
    }
    void divide(int v,int p)
    {
        ans+=solve(v,0);
        vis[v]=1;
        for(int i=head[v];i!=-1;i=G[i].nxt)
        {
            int t=G[i].to;
            if(t==p||vis[t])
                continue;
            ans-=solve(t,G[i].len);
            minn=N;
            tn=sz[t];//注意子树的大小,是在该子树中找重心!!!!
            dfs(t,0);
            divide(focus,0);
        }
    }
    int main()
    {
        int n,u,v,l;
        while(scanf("%d%d",&n,&k),n||k)
        {
            ans=0;
            init();
            memset(vis,false,sizeof(vis));
            for(int i=1;i<n;i++)
            {
                read(u),read(v),read(l);
                addedge(u,v,l);
                addedge(v,u,l);
            }
            tn=n,minn=N;
            dfs(1,0);//找到最开始树的重心
            divide(focus,0);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    

    上面的代码要用容斥减去不满足条件的部分。
    或者直接对子树处理即可,见D Tree HDU - 4812

  • 相关阅读:
    安裝Node.js
    es match、match_phrase、query_string和term的区别
    ES系列十、ES常用查询API
    ElasticSearch 入门总结
    起立,老师好
    像哆啦A梦懂大雄一样懂客户,我们也会拥有百宝箱
    阿里云居然在偷偷发福利!
    别人家的公司又来了,这次竟然开起了演唱会
    听说国家博物馆收藏了一行代码 ???
    我还是那个我,为啥就被老板区别对待了呢?
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12697078.html
Copyright © 2011-2022 走看看