• 巧克力之树 [点分治+树状数组]


    题面

    思路

    路径问题?当然是点分治啊

    最大最小值的差查询......嗯,虽然不知道为什么,但是树状数组求逆序对一定能处理!(暴论)

    所以方法就确定了啦~(-_-||)

    点分治,每次先dfs一遍,搞出来当前分治块里面每个点到分治中心的路径上边权最大最小值,如果最大值减去最小值大于K就丢掉

    然后,我们把所有在本次分治中出现的值离散化,并且把每个点按照最大值排序

    我们对于排好序的点序列中的每一个点,每次用树状数组求出它前面有多少个点的最小值在$maxn-K$到$maxn$范围内

    这样可以做到不重复不遗漏(不流失不蒸发【大雾】)

    然后不要忘记在进入儿子的分治块之前先去重一下

    Code

    比较恶心......

    据说此题有LCT做法,我太蒻了不会qwq

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    inline int read(){
        int re=0,flag=1;char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-') flag=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
        return re*flag;
    }
    int n,K,first[100010],cnte,siz[100010],sum,root,son[100010];
    struct edge{
        int to,next,w;
    }a[200010];
    inline void add(int u,int v,int w){
        a[++cnte]=(edge){v,first[u],w};first[u]=cnte;
        a[++cnte]=(edge){u,first[v],w};first[v]=cnte;
    }
    int vis[100010];
    void getroot(int u,int f){
        int i,v;siz[u]=1;son[u]=0;
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;if(v==f||vis[v]) continue;
            getroot(v,u);
            siz[u]+=siz[v];
            son[u]=max(son[u],siz[v]);
        }
        son[u]=max(son[u],sum-siz[u]);
        if(son[u]<son[root]) root=u;
    }
    struct node{
        int u,sub,minn,maxn;
    }x[100010];int cntx;
    inline bool cmp(node l,node r){
        return l.maxn<r.maxn;
    }
    void getinfo(int u,int f,int maxn,int minn,int sub){
        int i,v;
        if((~maxn)&&(~minn)){
            if(maxn-minn<=K){
                cntx++;
                x[cntx]=(node){u,sub,minn,maxn};
            }
            else return;
        }
        else maxn=-2e9,minn=2e9;
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;if(v==f||vis[v]) continue;
            getinfo(v,u,max(maxn,a[i].w),min(minn,a[i].w),(f==0)?v:sub);
        }
    }
    int d[200010],cntd;
    void lisan(){
        int i;
        cntd=0;
        for(i=1;i<=cntx;i++){
            d[++cntd]=x[i].minn;
            d[++cntd]=x[i].maxn;
        }
        sort(d+1,d+cntd+1);
        cntd=unique(d+1,d+cntd+1)-d-1;
        for(i=1;i<=cntx;i++){
            x[i].maxn=lower_bound(d+1,d+cntd+1,x[i].maxn)-d;
            x[i].minn=lower_bound(d+1,d+cntd+1,x[i].minn)-d;
        }
        sort(x+1,x+cntx+1,cmp);
    }
    struct BIT{
        int a[200010],len;
        void clear(int llen){
            for(int i=1;i<=len;i++) a[i]=0;
            len=llen;
        }
        int lowbit(int x){
            return x&(-x);
        }
        void add(int x,int val){
            for(;x<=len;x+=lowbit(x)) a[x]+=val;
        }
        int sum(int x){
            int re=0;
            for(;x>0;x-=lowbit(x)) re+=a[x];
            return re;
        }
    }T;
    int getpos(int pos){
        return lower_bound(d+1,d+cntd+1,pos)-d;
    }
    ll calc(int u){
        int i,pos;ll re=0,sum=0;
        T.clear(cntd);
        for(i=1;i<=cntx;i++){
            if(u&&x[i].sub!=u) continue;
            sum++;
            pos=getpos(d[x[i].maxn]-K);
            re+=T.sum(x[i].maxn)-T.sum(pos-1);
            T.add(x[i].minn,1);
        }
        return re+(u?0:sum);
    }
    ll ans=0;
    void dfs(int u,int sz){
        int i,v;vis[u]=1;cntx=0;
        getinfo(u,0,-1,-1,-1);
        lisan();
        ans+=calc(0);
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;if(vis[v]) continue;
            ans-=calc(v);
        }
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;if(vis[v]) continue;
            sum=((siz[v]>siz[u])?(sz-siz[u]):siz[v]);
            root=0;son[0]=sum;
            getroot(v,0);
            dfs(root,sum);
        }
    }
    int main(){
        memset(first,-1,sizeof(first));
        n=read();K=read();int i,t1,t2,t3;
        for(i=1;i<n;i++){
            t1=read();t2=read();t3=read();
            add(t1,t2,t3);
        }
        sum=n;root=0;son[0]=n;
        getroot(1,0);
        dfs(root,n);
        printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    完全背包
    二分求值(二分适合求答案在两个数之间的题目)
    set<pair<int,int> >的用法
    01背包 (dp专题)
    矩阵快速幂
    BZOJ1977 [BeiJing2010组队]次小生成树 Tree
    BZOJ1854 [Scoi2010]游戏
    BZOJ1054 [HAOI2008]移动玩具
    NOIP系列复习及题目集合
    BZOJ2708 [Violet 1]木偶
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9606941.html
Copyright © 2020-2023  润新知