HDU5877 线段树,离散化,Dfs


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define memset(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define MAXM 200100 //1e5+10 为何不可
using namespace std;
ll K;
int n;
ll a[MAXM];//!!因为b[i]=k/a[i]
ll b[MAXM];
int access[MAXM];
int total;
ll ans;
int head[MAXM];
int number[MAXM<<3];
int m;//线段树,离散化后,最大长度
struct EDGE{
    int v;//到达点
    int last;//同一点出发的上一条边,初始边是-1
}Edge[MAXM];
void Add(int u,int v){
    Edge[total].v=v;
    Edge[total].last=head[u];
    head[u]=total++;
}
/*
void Build(int root,int l,int r){
    if(l==r){
        number[root]=0;
        return ;
    }
    int mid=(l+r)/2;
    int subroot_l=root<<1;
    int subroot_r=subroot_l+1;
    Build(subroot_l,l,mid);
    Build(subroot_r,mid+1,r);
    number[root]=number[subroot_l]+number[subroot_r];
    return;
}
*/
int Query(int root,int l,int r,int x,int y){
    if(l==x&&r==y){//l>=x&&r<=y
        return number[root];
    }
    int mid=(l+r)/2;
    int subroot_l=root<<1;
    int subroot_r=subroot_l+1;
    if(y<=mid){
        return Query(subroot_l,l,mid,x,y);
    }
    else if(x>=mid+1){
        return Query(subroot_r,mid+1,r,x,y);
    }
    else{
        return Query(subroot_l,l,mid,x,mid)+Query(subroot_r,mid+1,r,mid+1,y);
    }
}
void Update(int root,int l,int r,int pos_update,int value_update){
    if(l==r){//不能写成l==pos_update或者r==pos_update
        number[root]+=value_update;
        return ;
    }
    int mid=(l+r)/2;
    int subroot_l=root<<1;
    int subroot_r=subroot_l+1;
    if(pos_update<=mid){
        Update(subroot_l,l,mid,pos_update,value_update);
    }
    else if(mid+1<=pos_update){
        Update(subroot_r,mid+1,r,pos_update,value_update);
    }
    number[root]=number[subroot_l]+number[subroot_r];//这一句不要忘记写!!递归往上回溯,不断更新每一层的各个区间。
}
void Dfs(int u){
    int pos_query=lower_bound(b+1,b+m+1,K/a[u])-b;/// -b,还是-(b+1)
    int pos_update=lower_bound(b+1,b+m+1,a[u])-b;
    ans+=1ll*Query(1,1,m,1,pos_query);//区间查询,所以传递的查询参数除了整个查询开始的范围(1,1,m)/* 如果建立的线段树不是像本题一样是个数组,而是节点node,每个节点有left,right,value,那么只需要1这个开始的节点的id即可,而本题这样的数组只存线段树每个节点的value那么就需要存储l、r每到一层都算一次*/,再加上查询区间的左边界(1)和右边界(pos_query)
    Update(1,1,m,pos_update,1);//单点更新,所以参数传递除了整个查询开始的范围,只需要更改点的位置(pos_update)以及更改数值(1)即可。
    for(int i=head[u];i!=-1;i=Edge[i].last) Dfs(Edge[i].v);
    Update(1,1,m,pos_update,-1);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        total=ans=0;
        memset(access,0);
        memset(head,-1);//Edge不用memset,只要head和total初始化即可
        scanf("%d%I64d",&n,&K);
        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
            b[i]=a[i];
            b[i+n]=K/a[i];
        }
        sort(b+1,b+1+2*n);//排序,离散化的基础
        m=unique(b+1,b+1+2*n)-(b+1);/// -b,还是-(b+1)
        //线段树的叶子(点)个数
        int u,v;
        //Build(1,1,m);// 没什么意义,因为建立的空的线段树,随后按题目中构造的树,从根部出发DFS顺序遍历,不断往线段树上加点和删点;
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            Add(u,v);
            access[v]++;
        }
        for(int i=1;i<=n;i++){
            if(access[i]==0) Dfs(i);
        }
        cout<<ans<<endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值