HDOJ 4366 - Successor 展开树为后序遍历,离线处理线段树..出现问题:读题错误..细节写错..爆栈..

              题意:

                         有一个由上下级关系构成的树...如果开除一个人..那么从他的子树里找一个能力比他强..并且忠诚度最高的(注意..不是比他高)..问若开除谁,,谁来顶替(注意..不是连续的过程..都是单独的...)

              题解:

                          完全2B了...读题各种错误..连ability和loyalty的读入都搞反..然后是忠诚度的要求搞错..排序的时候少考虑了(能力相等..父节点在子节点前面)...写线段树的时候又犯些2B的错误..而且还莫名其妙的爆栈....只带一个参数走..dfs里也只定义了一个参数..这也能爆栈?没办法..只能前面加申请栈空间代码...这题要把我做蒙了..还好提交十多次终于AC了..思路一开始就没错...真是蛋疼...

                          题解思路很简单...离线打表..O(1)输出...为了方便线段树的查询..找出该树的后序遍历(DFS回朔标记即可...)..发现其孩子都在他左边的某一片区域...一颗二维的树就变成了一个一维的...用线段树点更新.区间查找最大值就好...每个staff按能力大小的顺序往线段树里添加..每次找他孩子所在区间的忠诚最大值..由于放入的时候保证了是按能力大小..也就是当本staff查询时..线段树中所存在staff的能力都比他大..所以只要找区间忠诚度最高的...

 

Program:

#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<stack>
#include<string.h>
#include<map>
#include<set>
#include<algorithm>
#define oo 1000000007
#define MAXN 50005
#define ll int
using namespace std; 
struct node
{
       int a,b,l,id;
}s[MAXN];
struct LINE
{
       int x,y,next;
}line[MAXN]; 
int Max[MAXN<<2],_next[MAXN];
int hash[1000005],ans[MAXN],dfn[MAXN],Lnum,N,num;
bool cmp(node a,node b) 
{ 
       if (a.b!=b.b) return a.b>b.b; 
       return dfn[a.id]>dfn[b.id];
}
void addline(int x,int y)
{
       line[++Lnum].next=_next[x],_next[x]=Lnum;
       line[Lnum].x=x,line[Lnum].y=y;
}
void dfs(int x)
{
       s[x].l=oo;
       for (int k=_next[x];k;k=line[k].next) 
       {
             dfs(line[k].y);
             s[x].l=min(s[x].l,s[line[k].y].l);
       }
       dfn[x]=num,s[x].l=min(s[x].l,num); 
       num++;
}
void update(int p,int c,int l,int r,int now)
{
       if (l==r) { Max[now]=c; return; }
       int mid=l+r>>1;
       if (p<=mid) update(p,c,l,mid,now<<1);
       if (p>mid)  update(p,c,mid+1,r,now<<1|1);
       Max[now]=max(Max[now<<1],Max[now<<1|1]); 
}
int query(int L,int R,int l,int r,int now)
{
       if (L<=l && R>=r) return Max[now];
       int mid=l+r>>1,ans=-oo;
       if (L<=mid) ans=max(ans,query(L,R,l,mid,now<<1));
       if (R>mid)  ans=max(ans,query(L,R,mid+1,r,now<<1|1));
       return ans;
}
int main()
{ 
       int cases,i,x,Q;   
       scanf("%d",&cases);
       while (cases--)
       {
                scanf("%d%d",&N,&Q);
                memset(_next,0,sizeof(_next)),Lnum=0;
                for (i=1;i<N;i++)
                {
                        scanf("%d%d%d",&x,&s[i].a,&s[i].b);
                        hash[s[i].a]=i,s[i].id=i;
                        addline(x,i);
                }
                s[0].a=s[0].b=oo; s[0].id=0;
                num=0; 
                dfs(0);
                sort(s,s+N,cmp);
                memset(Max,-0x3f,sizeof(Max)); 
                for (i=0;i<N;i++)
                {
                        x=query(s[i].l,dfn[s[i].id],0,N-1,1);
                        if (x<0) ans[s[i].id]=-1;
                                 else ans[s[i].id]=hash[x];
                        update(dfn[s[i].id],s[i].a,0,N-1,1);
                }
                while (Q--)
                {
                        scanf("%d",&x);
                        printf("%d\n",ans[x]);
                }
       }
       return 0;
} 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值