zoukankan      html  css  js  c++  java
  • P4178 Tree(点分治)

    没想到一发直接过了啊

    思路

    点分治

    二分小于等于k的位置即可

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int middis[40010],midcnt,n,k,u[40010<<1],v[40010<<1],w[40010<<1],cnt,fir[40010],nxt[40010<<1],sz[40100],f[40100],root,vis[40100],Siz;
    long long ans=0;
    void addedge(int ui,int vi,int wi){
        ++cnt;
        u[cnt]=ui;
        v[cnt]=vi;
        w[cnt]=wi;
        nxt[cnt]=fir[ui];
        fir[ui]=cnt;
    }
    void findroot(int u,int fa){
        f[u]=1;
        sz[u]=1;
        for(int i=fir[u];i;i=nxt[i]){
            if(v[i]==fa||vis[v[i]])
                continue;
            findroot(v[i],u);
            sz[u]+=sz[v[i]];
            f[u]=max(f[u],sz[v[i]]);
        }
        f[u]=max(Siz-f[u],f[u]);
        if(f[root]>f[u])
            root=u;
    }
    void getdis(int u,int d,int fa){
        middis[++midcnt]=d;
        for(int i=fir[u];i;i=nxt[i]){
            if(v[i]==fa||vis[v[i]])
                continue;
            getdis(v[i],d+w[i],u);
        }
    }
    int look(int l,int k){
        int ans=0,r=midcnt;
        while(l<=r){
            int mid=(l+r)>>1;
            if(middis[mid]<=k)
                ans=mid,l=mid+1;
            else
                r=mid-1;
        }
    }
    int solve(int u,int d,int fa){
        midcnt=0;
        getdis(u,d,fa);
        sort(middis+1,middis+midcnt+1);
        int l=1,ans=0;
        // ans+=look(1,k);
        while(l<midcnt&&k-middis[l]>=middis[l]){
            int lx=look(l+1,k-middis[l]);
            if(lx>l)
                ans+=lx-l-1;
            l++;
        }
        return ans;
    }
    void divide(int u){
        // printf("%d
    ",u);
        // getchar();
        vis[u]=true;
        ans+=solve(u,0,0);
        // printf("ans=%d
    ",ans);
        for(int i=fir[u];i;i=nxt[i]){
            if(vis[v[i]])
                continue;
            ans-=solve(v[i],w[i],u);
            root=0;
            Siz=sz[v[i]];
            findroot(v[i],u);
            divide(root);
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n-1;i++){
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            addedge(a,b,c);
            addedge(b,a,c);
        }
        scanf("%d",&k);
        Siz=n;
        f[0]=0x3f3f3f3f;
        findroot(1,0);
        divide(root);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    印刷行业合版BOM全阶维护示例
    C#实现WinForm禁止最大化、最小化、双击标题栏、双击图标等操作的方法
    EasyUI Tree节点拖动到指定容器
    Excel GET.DOCUMENT说明
    Excel GET.CELL说明
    ExecuteExcel4Macro (宏函数)使用说明
    MSSQL:查看所有触发器信息的命令
    SQL Server 2008作业失败:无法确定所有者是否有服务器访问权限
    Cocoa History
    Working with Methods
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10093323.html
Copyright © 2011-2022 走看看