zoukankan      html  css  js  c++  java
  • 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结

    推荐你谷ysn等巨佬的详细题解

    大致流程——

    1. dfs求出当前树的重心

    2. 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成)

    3. 容斥减去不合法情况(两条子路径在重心的子树内就已经相交)

    4. 删除重心(打上永久标记),对子树继续处理,转1

    求重心是板子,算答案的方法要依题而定,一般都要容斥。

    模板题洛谷传送门

    calc函数中,头尾两个指针扫的计数方法也是一种套路

    因为要sort,所以复杂度(O(nlog^2n)),不过蒟蒻实测你谷数据(k)不超过(40000),所以可以改用桶排序,复杂度降到(O(n(log n+log k)))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define RG register
    #define I inline
    #define R RG int
    #define G c=getchar()
    using namespace std;
    const int N=4e5+9,M=8e5+9;
    int n,k,p,rt,ans,he[N],ne[M],to[M],l[M],mx[N],s[N],b[N];
    bool vis[N];
    I void max(R&x,R y){if(x<y)x=y;}
    I int in(){
        RG char G;
        while(c<'-')G;
        R x=c&15;G;
        while(c>'-')x*=10,x+=c&15,G;
        return x;
    }
    void getrt(R x){//求重心模板
        vis[x]=1;s[x]=1;mx[x]=0;
        for(R y,i=he[x];i;i=ne[i]){
            if(vis[y=to[i]])continue;
            getrt(y);
            s[x]+=s[y];max(mx[x],s[y]);
        }
        max(mx[x],n-s[x]);
        if(mx[rt]>mx[x])rt=x;
        vis[x]=0;
    }
    void getd(R x,R d){//统计长度不超过k的子路径
        if(d>k)return;
        vis[x]=1;b[++p]=d;
        for(R i=he[x];i;i=ne[i])
            if(!vis[to[i]])getd(to[i],d+l[i]);
        vis[x]=0;
    }
    I int calc(R x,R dis){//计算经过x的路径的答案
        p=0;getd(x,dis);
        sort(b+1,b+p+1);
        R ret=0,i=1,j=p;//双指针扫描计数
        while(i<=j)b[i]+b[j]>k?--j:ret+=j-i++;
        return ret;
    }
    void div(R x){//分治流程在此函数中得到体现
        getrt(x);
        ans+=calc(x=rt,0);
        vis[x]=1;rt=0;
        for(R t=n,y,i=he[x];i;i=ne[i]){
            if(vis[y=to[i]])continue;
            ans-=calc(y,l[i]);
            n=s[x]>s[y]?s[y]:t-s[x];
            div(y);
        }
    }
    int main(){
        mx[0]=1e9;
        n=in();
        for(R x,y,i=1;i<n;++i){
            x=in();y=in();
            ne[++p]=he[x];to[he[x]=p]=y;
            ne[++p]=he[y];to[he[y]=p]=x;
            l[p]=l[p-1]=in();
        }
        k=in();
        div(1);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    _bzoj1061 [Noi2008]志愿者招募【最小费用最大流】
    _bzoj2243 [SDOI2011]染色【树链剖分】
    _bzoj1013 [JSOI2008]球形空间产生器sphere【高斯消元】
    _bzoj1002 [FJOI2007]轮状病毒【瞎搞】
    leetcode 273 Integer to English Words
    leetcode 12 Integer to Roman
    leetcode 1071 Greatest Common Divisor of Strings
    lc6 ZigZag Conversion
    lc13 Roman to Integer
    leetcode 171 Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/flashhu/p/9351535.html
Copyright © 2011-2022 走看看