zoukankan      html  css  js  c++  java
  • POJ 1741 树分治

    Tree
    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 23829   Accepted: 7900

    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.

    Sample Input

    5 4
    1 2 3
    1 3 1
    1 4 2
    3 5 1
    0 0
    

    Sample Output

    8

    Source

     
     
    树分治:
    分治很清楚是指分而治之,树就分成了子树,但是怎么分才能是的分才最适合呢? 
    就像快速排序一样,也有可能退化,于是,用树的重心,这个DP很容易,但是,要每棵子树都要求重心呢?
     
    以某一棵子树为研究对象,有多少个点对满足 d[i] + d[j] <= k 呢?
    对这个子树 dfs求出 d ,距离 “根” 的距离(这个根是变化的);
    将所有 d排序,扫描即可。
     
    从根出发,递归到子节点,子节点再求,这样子节点求得的会有一部分重合。减去经过父亲结点的那些 <= k 的点对(此时,就是求以子节点为根,系数相差 d[f][v] 的 点对)。
     
    至此,这个关于 点的 树分治,就解决了!!!
    男人八题写了3题了。
     
    另外,此题可以当做树分治模板,当然,这里没有用到LCA,还有很多高级操作没有,但是树分治的框架差不多是这样,变的就是其中的统计函数。
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    
    
    using namespace std;
    
    #define N 10005
    
    struct Node {
        int v,l;
    };
    
    vector<Node> g[N];
    
    int n,k;
    
    int s[N],f[N];
    bool done[N];
    int size;
    int root;

    // 当前子树的重心
    void getroot(int u,int fa) { s[u] = 1; f[u] = 0; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { getroot(v,u); s[u] +=s[v]; f[u] = max(f[u],s[v]); } } f[u] = max(f[u],size-s[u]); if(f[u]<f[root]) root = u; } vector<int> dep; int d[N];

    //当前子树的重心下,节点到重心的距离
    void getdep(int u,int fa) { dep.push_back(d[u]); s[u] = 1; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { d[v] = d[u] + g[u][i].l; getdep(v,u); s[u]+=s[v]; } } }
    //统计函数
    int calc(int u,int init) { dep.clear(); d[u] = init; getdep(u,0); sort(dep.begin(),dep.end()); int ret = 0; for(int l=0,r=dep.size()-1;l<r;) if(dep[l]+dep[r]<=k) ret += r-l++; else r--; return ret; }
    //树分治整体框架
    int ans; void work(int u) { ans+=calc(u,0); done[u] = true; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(!done[v]) { ans-=calc(v,g[u][i].l); f[0] = size = s[v]; getroot(v,root=0); work(root); } } } int main() { while(scanf("%d%d",&n,&k),n) { for(int i=0; i <= n; i++) g[i].clear(); memset(done,0,sizeof(done)); int u,v,l; for(int i=1; i < n; i++) { scanf("%d%d%d",&u,&v,&l); g[u].push_back((Node){v,l}); g[v].push_back((Node){u,l}); } f[0] = size = n; getroot(1,root=0); ans = 0; work(root); printf("%d ",ans); } return 0; }
     
     
     
     
     
     
  • 相关阅读:
    IE浏览器不能启动,双击启动图标无效
    提示Internet Explorer 9 已安装在此系统上,无法完成安装
    React项目跨域处理(两种方案)
    Mock数据模拟Node服务器
    【LeetCode】15. 3Sum
    【C++】int与string互转
    【LeetCode】37. Sudoku Solver
    【LeetCode】149. Max Points on a Line
    【LeetCode】104. Maximum Depth of Binary Tree (2 solutions)
    【LeetCode】140. Word Break II
  • 原文地址:https://www.cnblogs.com/TreeDream/p/7436015.html
Copyright © 2011-2022 走看看