HDU 5877 [dfs序][线段树][序]

/*
题意:
n个点的树,每个点给定一个权值,给定一个k,求任意一点的子树中,权值小于k/该点权值的点共有多少个。
思路:
1.很明显的子树的操作,应用dfs序。
2.比赛的时候傻逼了,一直在调划分树。实际上这题考虑序关系,加树状数组或者线段树就可以搞定了。
3.序关系:将权值按照从大到小的顺序排序进行查询,然后按照从小到大的顺序排序进行插入。
*/



#include<bits/stdc++.h>
#define N 100050
using namespace std;
int ednum;
struct edge{
    int id;
    edge *next;
};
edge edges[N];
edge *adj[N];
struct tr{
    int s,e,num;
};
tr tree[N*4];
void build(int s,int e,int k){
    tr &tmp=tree[k];
    tmp.s=s;tmp.e=e;tmp.num=0;
    if(s==e)return;
    int mid=(s+e)>>1;
    build(s,mid,k<<1);
    build(mid+1,e,k<<1|1);
}
int cha(int s,int e,int k){
    tr &tmp=tree[k];
    if(tmp.s==s&&tmp.e==e)return tmp.num;
    int mid=(tmp.s+tmp.e)>>1;
    if(e<=mid)return cha(s,e,k<<1);
    else if(s>mid)return cha(s,e,k<<1|1);
    else return cha(s,mid,k<<1)+cha(mid+1,e,k<<1|1);
}
void ins(int pos,int k){
    tr &tmp=tree[k];
    if(tmp.s==tmp.e){
        tmp.num++;
        return;
    }
    int mid=(tmp.s+tmp.e)>>1;
    if(pos<=mid)ins(pos,k<<1);
    else ins(pos,k<<1|1);
    tmp.num=tree[k<<1].num+tree[k<<1|1].num;
}
inline void addedge(int a,int b){
    edge *tmp=&edges[ednum++];
    tmp->id=b;
    tmp->next=adj[a];
    adj[a]=tmp;
}
struct st{
    int id;
    long long val;
};
bool cmp1(st a,st b){
    return a.val<b.val;
}
bool cmp2(st a,st b){
    return a.val>b.val;
}
st sol1[N],sol2[N];
long long jilu[N];
int from[N];
int id[N],siz[N];
int dfn;
void dfs(int pos){
    id[pos]=dfn++;
    siz[pos]=1;
    for(edge *it=adj[pos];it;it=it->next){
        dfs(it->id);
        siz[pos]+=siz[it->id];
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(adj,NULL,sizeof(adj));
        memset(from,0,sizeof(from));
        ednum=0;
        int n;
        long long k;
        scanf("%d%lld",&n,&k);
        build(1,n,1);
        for(int i=1;i<=n;i++){
            scanf("%lld",jilu+i);
            sol1[i].id=i;
            sol1[i].val=jilu[i];
            sol2[i]=sol1[i];
        }
        sort(sol1+1,sol1+1+n,cmp1);
        sort(sol2+1,sol2+1+n,cmp2);
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            addedge(a,b);
            from[b]=a;
        }
        int st=1;
        while(from[st]){
            st=from[st];
        }
        dfn=1;
        dfs(st);
        int bf=1;
        long long ans=0;
        for(int i=1;i<=n;i++){
            while(bf<=n&&sol1[bf].val<=k/sol2[i].val){
                ins(id[sol1[bf].id],1);
                bf++;
            }
            ans+=cha(id[sol2[i].id],id[sol2[i].id]+siz[sol2[i].id]-1,1);
            ans-=cha(id[sol2[i].id],id[sol2[i].id],1);
        }
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/tun117/p/5900534.html