hdu5877 Weak Pair(线段树+离散化)

hdu5877

题目

就是给你一颗有根树,对于两个有序节点对u,v满足两个条件,u是v的父亲,au*av<=k则算作是一个Weak Pair,求总Weak Pair。

思路

一开始还想往树型dp套套套,结果队友提醒了下,但是没注意到有根树,离散化的也不是很好,没A。
其实无非就是区间查询,单点增删的线段树,离散化要把k/a[i]也给离散化了。对于一个节点先查询来到它的路径上满足要求的个数,然后插入它,然后递归子节点,在结束时删除它即可。

代码

#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

typedef long long ll;
const ll maxn=1e5+100;

int n,numm,head[maxn],tot,deep[maxn];
ll num[maxn],ans,k,x[2*maxn];
ll sum[(2*maxn)<<2];

void PushUP(ll rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void build(ll l,ll r,ll rt)
{
    if(l==r)
    {
        sum[rt]=0;
        return;
    }
    ll m=(l+r) >> 1;
    build(lson);
    build(rson);
    PushUP(rt);
}

void update(ll p,ll add,ll l,ll r,ll rt)
{
    if(l==r)
    {
        sum[rt]+=add;
        return;
    }
    ll m=(l+r) >> 1;
    if(p<=m) update(p,add,lson);
    else update(p,add,rson);
    PushUP(rt);
}

ll query(ll L,ll R,ll l,ll r,ll rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    ll ret=0;
    ll m=(l+r) >> 1;
    if(L<=m) ret+=query(L,R,lson);
    if(R>m) ret+=query(L,R,rson);
    return ret;
}

struct node
{
    int next;
    int to;
} edge[maxn];

void addedge(int from,int to)
{
    edge[tot].to=to;
    edge[tot].next=head[from];
    head[from]=tot++;
}

void dfs(int u,int fa)
{
    int o=lower_bound(x,x+numm,k/num[u])-x;
    ans+=query(0,o,0,numm,1);

    int kk=lower_bound(x,x+numm,num[u])-x;
    update(kk,1,0,numm,1);
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to;
        dfs(v,u);
    }
    update(kk,-1,0,numm,1);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %I64d",&n,&k);
        int cnt=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%I64d",&num[i]);
            x[cnt++]=num[i];
        }
        for(int i=1; i<=n; i++)
            x[cnt++]=k/num[i];

        sort(x,x+cnt);
        numm=unique(x,x+cnt)-x;

        tot=0;
        memset(head,-1,sizeof(head));
        memset(deep,0,sizeof(deep));

        for(int i=0; i<n-1; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v);
            deep[v]++;
        }

        ans=0;
        build(0,numm,1);
        for(int i=1; i<=n; i++)
            if(deep[i]==0)
                dfs(i,-1);
        printf("%I64d\n",ans);
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值