• POJ1741Tree [点分治]【学习笔记】


    Tree
    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 20098   Accepted: 6608

    Description

    Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
    Define dist(u,v)=The min distance between node u and v. 
    Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
    Write a program that will count how many pairs which are valid for a given tree. 

    Input

    The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
    The last test case is followed by two zeros. 

    Output

    For each test case output the answer on a single line.

    题意:给一颗带权树,求树上长度不超过L的路径条数

    首先有一个有树高限制时的树形DP做法..........
     

    对于一条树路径 只有经过或不经过一个点的情况

    考虑经过一个点的路径,可以由其他点到它的两条路径拼出来

    对于不经过的情况 把一棵树按这个点拆成好几棵分治
     
    每次对于当前子树选择树的重心,最多递归logn次,而每层最多只有n个点(每层的所有子树组成整棵树),复杂度O(logn*处理每层的复杂度)
     
    过程:
    1.求重心
    2.处理经过当前点的路径
    3.对子树分治
     
    每次分治的各个子树是互不影响的,vis[i]表示i这个点已经分治过了
     
    注意:既然你的写法是先找重心在递归,那么一定要rt=0;dfsRt(v,0);dfsSol(rt);是rt啊啊啊啊啊不是v了
     
    对于本题,处理经过点u的路径时,先dfs子树中所有点对深度,排序两个指针往里扫计算<=L的,在减去在同一颗子树里的(同样计算)
    总复杂度O(nlog^2n)
     
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=10005,INF=1e9+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,L,u,v,w;
    struct edge{
        int v,w,ne;
    }e[N<<1];
    int h[N],cnt;
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    
    int size[N],d[N],vis[N],root,sum;
    void dfsRoot(int u,int fa){
        size[u]=1;d[u]=0;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            dfsRoot(v,u);
            size[u]+=size[v];
            d[u]=max(d[u],size[v]);
        }
        d[u]=max(d[u],sum-size[u]);
        if(d[u]<d[root]) root=u;
    }
    int deep[N],a[N];
    void dfsDeep(int u,int fa){
        a[++a[0]]=deep[u];
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            deep[v]=deep[u]+e[i].w;
            dfsDeep(v,u);
        }
    }
    
    int cal(int u,int now){
        deep[u]=now;a[0]=0;
        dfsDeep(u,0);
        sort(a+1,a+1+a[0]);
        int l=1,r=a[0],ans=0;
        while(l<r){
            if(a[l]+a[r]<=L) ans+=r-l,l++;
            else r--;
        }
        return ans;
    }
    int ans;
    void dfsSol(int u){//printf("dfs %d
    ",u);
        vis[u]=1;
        ans+=cal(u,0);
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]) continue;
            ans-=cal(v,e[i].w);
            sum=size[v];
            root=0;dfsRoot(v,0);
            dfsSol(root);
        }
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        while(true){
            n=read();L=read();if(n==0) break;
            cnt=0;memset(h,0,sizeof(h));
            memset(vis,0,sizeof(vis));
            ans=0;
            for(int i=1;i<=n-1;i++) u=read(),v=read(),w=read(),ins(u,v,w);
            sum=n;
            root=0;d[0]=INF;
            dfsRoot(1,0);
            dfsSol(root);
            printf("%d
    ",ans);
        }
    }
     还有一种做法,用treap维护,考虑经过每个点的路径时,建一颗treap维护长度,每个点加上之前遍历过的这点的子树中<L-deep[v]+1的,最后再把这棵子树的所有深度加入treap
     
     
    //
    //  main.cpp
    //  treap
    //
    //  Created by Candy on 2017/1/9.
    //  Copyright ? 2017年 Candy. All rights reserved.
    //
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define lc t[x].l
    #define rc t[x].r
    const int N=1e5+5,INF=1e9;
    int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    struct node{
        int l,r,v,w,size,rnd;
    }t[N];
    int sz,root;
    inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
    inline void lturn(int &x){
        int c=rc;rc=t[c].l;t[c].l=x;
        t[c].size=t[x].size;update(x);x=c;
    }
    inline void rturn(int &x){
        int c=lc;lc=t[c].r;t[c].r=x;
        t[c].size=t[x].size;update(x);x=c;
    }
    void ins(int &x,int v){
        if(x==0){
            x=++sz;
            t[x].l=t[x].r=0;
            t[x].v=v;t[x].w=t[x].size=1;
            t[x].rnd=rand();
            return;
        }
        t[x].size++;
        if(v==t[x].v) t[x].w++;
        else if(v<t[x].v){
            ins(lc,v);
            if(t[lc].rnd<t[x].rnd) rturn(x);
        }else{
            ins(rc,v);
            if(t[rc].rnd<t[x].rnd) lturn(x);
        }
    }
    int que(int x,int v){//cnt of <v
        if(!x) return 0;
        if(t[x].v==v) return t[lc].size;
        if(v<t[x].v) return que(lc,v);
        else return t[lc].size+t[x].w+que(rc,v);
    }
    
    int n,L,u,v,w;
    struct edge{
        int v,w,ne;
    }e[N<<1];
    int h[N],cnt;
    inline void ins(int u,int v,int w){
        cnt++;
        e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt;
    }
    int vis[N],size[N],f[N],sum,rt;
    void dfsRoot(int u,int fa){
        size[u]=1;f[u]=0;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            dfsRoot(v,u);
            size[u]+=size[v];
            f[u]=max(f[u],size[v]);
        }
        f[u]=max(f[u],sum-size[u]);
        if(f[u]<f[rt]) rt=u;
    }
    
    int ans,deep[N];
    void dfsDeep(int u,int fa,int p){
        if(p==0) ans+=que(root,L-deep[u]+1);
        else ins(root,deep[u]);
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]||v==fa) continue;
            deep[v]=deep[u]+e[i].w;
            dfsDeep(v,u,p);
        }
    }
    void dfsSol(int u){//printf("sol %d
    ",u);
        vis[u]=1;
        sz=root=0;
        ins(root,0);
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]) continue;
            deep[v]=e[i].w;
            dfsDeep(v,u,0);
            dfsDeep(v,u,1);
        }
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(vis[v]) continue;
            sum=size[v];
            rt=0;dfsRoot(v,u);
            dfsSol(rt);
        }
    }
    int main(){
        //freopen("in.txt","r",stdin);
        while(true){
            n=read();L=read();if(n==0) break;
            cnt=0;memset(h,0,sizeof(h));
            memset(vis,0,sizeof(vis));
            ans=0;
            for(int i=1;i<=n-1;i++) u=read(),v=read(),w=read(),ins(u,v,w);
            sum=n;
            rt=0;f[0]=INF;
            dfsRoot(1,0);
            dfsSol(rt);
            printf("%d
    ",ans);
        }
    }
     
     
  • 相关阅读:
    JavaSE 窗口事件类(WindowEvent)实现
    ChemBioDraw 制作DMT屏保
    Sourcery G++ Lite 2009q3-67 ARM交叉工具链【分享】
    Beej's Guide to C Programming 【分享】
    囚徒健身 mobi 【分享】
    屏幕录像专家2011build1226 【分享】
    Fraps3.4.7 注册版【分享】
    一步步学习微软InfoPath2010和SP2010--第十三章节--SharePoint视图和仪表板(1)--服务台请求
    一步步学习微软InfoPath2010和SP2010--第十三章节--SharePoint视图和仪表板
    一步步学习微软InfoPath2010和SP2010--第十二章节--管理和监控InfoPath Form Services(IPFS)(7)--关键点
  • 原文地址:https://www.cnblogs.com/candy99/p/6266700.html
Copyright © 2020-2023  润新知