HDU 4366(Successor-块状链表)

给一棵树(2<=n<=50000)个节点,每个节点有2个点权”忠诚”与”能力”
所有节点”忠诚”各不相同,现在有m个询问,每次对第i个节点,求出其子树中”能力”>它的节点中”忠诚”最高的那个

先求出dfs序,分 n
每段按能力排序,预处理每段到i到末尾能取的最大忠诚
复杂度 O(nnlogn)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<map>
#include<iomanip> 
#include<vector>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define MAXN (55000+10)
int n,m;
vi e[MAXN];
int l[MAXN],r[MAXN],ti[MAXN];
pi a[MAXN];
void dfs(int x,int &T) {
    l[x]=++T;
    ti[T]=x;
    for(auto v:e[x]) {
        dfs(v,T);
    }
    r[x]=T;
}
map<int,int> h;
int blo,le;
int cmp(int x,int y) {
    if (x==-1||y==-1) return x<y;
    return a[x].fi<a[y].fi;
}
int sorted[MAXN],ma[MAXN];

int work(int l,int r,int x) {
    int ans=r+1;
    while (l<=r) {
        int m=(l+r)>>1;
        if (a[sorted[m]].fi <=x) l=m+1;
        else r=m-1,ans=m;
    }
    return ans;
}


int main()
{
//  freopen("hdu4366_data.out","r",stdin);
//  freopen("hdu4366.out","w",stdout);

    int T=read();
    while(T--) {
        h.clear();
        int n=read(),m=read();
        For(i,n-1) {
            int u=read();
            e[u].pb(i);
            a[i].se=read(); a[i].fi=read();
            h[a[i].se]=i;
        }
        int t=0;
        dfs(0,t);

        blo=250;
        le=t/blo;

        For(i,t) sorted[i]=ti[i];

        For(i,le)
        { 
            sort(sorted+(i-1)*blo+1,sorted+i*blo+1,cmp);
        }

        ForD(i,le*blo) {
            ma[i]=a[sorted[i]].se;
            if (i%blo) 
                ma[i]=max(ma[i],ma[i+1]);
        }

        while(m--) {
            int x;
            scanf("%d",&x);
            int L=l[x]+1,R=r[x];
            if (L>R) {printf("-1\n");continue;}
            int ans=-1;
            for(int i=L;i<=R;)
                if ( i % blo == 1 && i + blo - 1 <= R ) {
                    if (a[sorted[i+blo-1]].fi<=a[x].fi ) {
                        i+=blo;
                        continue;
                    }
                    if (a[sorted[i]].fi>a[x].fi) {
                        ans=max(ans, ma[i] );
                        i+=blo; 
                        continue;
                    } //这个优化必选加 
//                  int p=upper_bound(sorted+i+1,sorted+i+blo,x,cmp)-(sorted); //这个函数不快但可用 
                    int p=work(i,i+blo-1,a[x].fi); 
                    if (p!=i+blo) {
                        ans=max(ans,ma[p]);
                    } 
                    i+=blo;
                } else {
                    if (a[x].fi<a[ti[i]].fi ) ans=max(ans,a[ti[i]].se);
                    i++;
                }
            printf("%d\n",ans==-1 ? ans:h[ans]);
        }


        Rep(i,n) e[i].clear();

    }   
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值