【2016-大连赛区网络赛-J】线段树,dfs(Weak Pair,hdu 5877)

本文分享了一道网络赛题目的解题思路及优化过程。作者最初尝试使用表达式树和间接排序的方法解决,但遇到了超时问题。通过参考他人解法并结合线段树、DFS和离散化技术,最终解决了问题。文中提供了两种不同实现方式的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/libin66/article/details/52497502


水平还是太差了,以前一直做水题,然而网络赛的题都是有些难度的,自己做了一个下午才AC。

比赛时有一个想法,实现了,理论上也不会超时,但是还是TLE了,不知道为啥。

具体方法就是写一个表达式树,每个数字代表一个节点,从而此数字后面的所有数字都是它的子节点。从后往前枚举每个数字,对这个数字后面的所有数字按ai进行间接排序,然后upper_bound坐标一减就是答案。O(nlogn),但超时了,然后就没再研究了。

参考了别人的方法,一直TLE或WA,而且找不到错,重写了几遍才AC,至少说明了TLE不一定是方法不对,也很有可能是你哪里细节没写好然后就死循环了?

他们的方法就是一边dfs一边维护线段树,同时计算答案,还用了离散化。具体怎么做不好说,看代码比较好。


两份代码:

一份是超时的那个。

一份是AC的。

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;

typedef long long ll;

ll N,k;
ll a[maxn];
ll id[maxn];
ll last[maxn];
ll r[maxn];
vector<ll>tree;
vector<ll>MAP[maxn];

void dfs(int u)
{
    tree.push_back(u);
    for(unsigned int i=0;i<MAP[u].size();i++)
        dfs(MAP[u][i]);
    last[u]=tree.size()-1;
}

bool cmp(ll x,ll y)
{
    return a[tree[x]]<a[tree[y]];
}

ll ub(ll* A,ll x,ll y,ll v)
{
    ll m;
    while(x<y)
    {
        m=x+(y-x)/2;
        if(a[tree[A[m]]]<=v) x=m+1;
        else y=m;
    }
    return x;
}

int main()
{
    ll T;
    scanf("%I64d",&T);
    while(T--)
    {
        tree.clear();
        tree.push_back(0);
        memset(id,0,sizeof(id));
        scanf("%I64d %I64d",&N,&k);
        for(ll i=1;i<=N;i++)
        {
            scanf("%I64d",&a[i]);
            r[i]=i;
            MAP[i].clear();
        }
        ll u,v;
        for(ll i=1;i<N;i++)
        {
            scanf("%I64d %I64d",&u,&v);
            MAP[u].push_back(v);
            id[v]++;
        }
        for(ll i=1;i<=N;i++)
            if(id[i]==0)
                dfs(i);
        ll ans=0;
        for(ll i=N;i>=1;i--)
        {
            sort(r+i+1,r+last[tree[i]]+1,cmp);
            //ans+=upper_bound(r+i+1,r+last[tree[i]]+1,k/a[tree[i]])-r-i-1;
            ans+=ub(r,i+1,last[tree[i]]+1,k/a[tree[i]])-i-1;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;

typedef long long ll;

ll tree[maxn<<3];
void A(ll l,ll r,ll now,ll pos,ll val)
{
    if(l==r) {tree[now]+=val;return;}
    ll m=(l+r)>>1;
    ll ls=now<<1;
    ll rs=ls|1;
    if(pos<=m) A(l,m,ls,pos,val);
    else A(m+1,r,rs,pos,val);
    tree[now]=tree[ls]+tree[rs];
}
ll Q(ll l,ll r,ll now,ll ql,ll qr)
{
    if(l>=ql&&r<=qr) return tree[now];
    ll m=(l+r)>>1;
    ll ls=now<<1;
    ll rs=ls|1;
    if(qr<=m) return Q(l,m,ls,ql,qr);
    else if(ql>m) return Q(m+1,r,rs,ql,qr);
    else return Q(l,m,ls,ql,qr)+Q(m+1,r,rs,ql,qr);
}

ll a[maxn];
ll b[maxn<<1];
ll id[maxn];
ll N,k,L,ans;
vector<ll>MAP[maxn];

void dfs(int u)
{
    ll pos=lower_bound(b+1,b+1+L,k/a[u])-b;
    ans+=Q(1,L,1,1,pos);
    pos=lower_bound(b+1,b+1+L,a[u])-b;
    A(1,L,1,pos,1);
    for(unsigned int i=0;i<MAP[u].size();i++) dfs(MAP[u][i]);
    A(1,L,1,pos,-1);
}

int main()
{
    ll T;
    scanf("%I64d",&T);
    while(T--)
    {
        scanf("%I64d %I64d",&N,&k);
        memset(id,0,sizeof(id));
        memset(tree,0,sizeof(tree));
        for(ll i=1;i<=N;i++)
        {
            scanf("%I64d",&a[i]);
            b[i]=a[i];
            b[i+N]=k/a[i];
            MAP[i].clear();
        }
        sort(b+1,b+1+2*N);
        L=unique(b+1,b+1+2*N)-b-1;
        ll u,v;
        for(ll i=1;i<N;i++)
        {
            scanf("%I64d %I64d",&u,&v);
            MAP[u].push_back(v);
            id[v]++;
        }
        ans=0;
        for(ll i=1;i<=N;i++)
            if(id[i]==0)
                dfs(i);
        printf("%I64d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值