hdu 4366 树形结构 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4366

题意:给你一棵树,每个结点有两个属性值,1:能力值   2:忠诚度

然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号


做法:

这种题还是老套路,将树形结构转换成线性结构,用数据结构来解决查询最值得问题。

但这个题目有一个亮点就是限制了一个变量,要求另一个变量满足第一个变量大于查询点的同时最大

其实仔细想一下也蛮简单的,将限制的那个变量按要求排序就好了,即从大到小排序,依次将能力大的点先插入线段树

线段树的话,就是对时间戳建树,dfs时每个点有一个进入的时间戳,还有一个出来的时间戳,这两个时间戳之间的点都属于这个点的子树

那么就可以在插入当前点之前先询问一下子树内的最大值,即(L[u],R[u])间的最大值 L[u]是进入u子树的时间戳,R[u]是出来的时间戳,这样的话可以处理处所有的点的结果(具体实现的时候要注意L R的边界情况)

然后询问的时候做到O(1)回答

附上一张我dfs时候的时间戳的图,左边的数字表示进去的时候的时间戳,右边的数字表示出来的时候的时间戳



show my code

#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
int Max[maxn<<2],ID[maxn<<2];
void pushup(int rt){
	if(Max[rt<<1]>Max[rt<<1|1]){
        Max[rt]=Max[rt<<1];
		ID[rt]=ID[rt<<1];
	}
	else {
		Max[rt]=Max[rt<<1|1];
		ID[rt]=ID[rt<<1|1];
	}
}
void build(int l,int r,int rt){
	Max[rt]=ID[rt]=-1;
	if(l==r) return ;
	int m=l+r>>1;
	build(lson);
	build(rson);
}
void update(int pos,int id,int val,int l,int r,int rt){
	if(l==r){
		ID[rt]=id;
		Max[rt]=val;
		return ;
	}
	int m=l+r>>1;
	if(pos<=m) update(pos,id,val,lson);
	else update(pos,id,val,rson);
	pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
	if(L>R)	return -1;
	if(L<=l&&r<=R){
		return Max[rt];
	}
	int m=(l+r)>>1;
	int ret=-1;
	if(L<=m) ret=max(ret,query(L,R,lson));
	if(R>m) ret=max(ret,query(L,R,rson));
	return ret;
}
int L[maxn],R[maxn];
struct node{
	int abty;
	int loty;
	int id;
	bool operator < (const node &cmp) const{
		return abty>cmp.abty;
	}
}in[maxn];
int ans[maxn];
vector<int> edge[maxn];
int tot;
void dfs(int u)   {
	L[u]=tot++;
	int sz=edge[u].size();
	for(int i=0;i<sz;i++)	{
		int v=edge[u][i];
		dfs(v);
	}
	R[u]=tot;
}
map<int,int> mp;
int main()  {
	int t,n,m;
	scanf("%d",&t);
	while(t--)	{
		mp.clear();
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n;i++) edge[i].clear();
		for(int i=1,fa;i<n;i++)	{
			scanf("%d%d%d",&fa,&in[i].loty,&in[i].abty);
			edge[fa].push_back(i);
			in[i].id=i;
			mp[in[i].loty]=i;
		}
		sort(in+1,in+n);
		tot=0;
		dfs(0);
		build(0,tot-1,1);
		memset(ans,-1,sizeof(ans));
	    for(int i=1,j;i<n;i=j)	{
			j=i;
			while(j<n && in[j].abty==in[i].abty)	{
		        int id=in[j].id;
				int lo=query(L[id]+1,R[id]-1,0,tot-1,1);
				ans[id]=  lo==-1 ? -1 :mp[lo];
				j++;
			}
			j=i;
			while(j<n && in[j].abty==in[i].abty)	{
				int id=in[j].id;
				update(L[id],id,in[j].loty,0,tot-1,1);
				j++;
			}
		}
		int u;
		while(m--)	{
			scanf("%d",&u);
			printf("%d\n",ans[u]);
		}
	}
	return 0;
}


可能会爆栈,要么用c++的方法加栈,要么就直接模拟栈吧。。

#include<cstdio>
#include<vector>
#include<map>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
int Max[maxn<<2],ID[maxn<<2];
void pushup(int rt){
    if(Max[rt<<1]>Max[rt<<1|1]){
        Max[rt]=Max[rt<<1];
        ID[rt]=ID[rt<<1];
    }
    else {
        Max[rt]=Max[rt<<1|1];
        ID[rt]=ID[rt<<1|1];
    }
}
void build(int l,int r,int rt){
    Max[rt]=ID[rt]=-1;
    if(l==r) return ;
    int m=l+r>>1;
    build(lson);
    build(rson);
}
void update(int pos,int id,int val,int l,int r,int rt){
    if(l==r){
        ID[rt]=id;
        Max[rt]=val;
        return ;
    }
    int m=l+r>>1;
    if(pos<=m) update(pos,id,val,lson);
    else update(pos,id,val,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L>R)    return -1;
    if(L<=l&&r<=R){
        return Max[rt];
    }
    int m=(l+r)>>1;
    int ret=-1;
    if(L<=m) ret=max(ret,query(L,R,lson));
    if(R>m) ret=max(ret,query(L,R,rson));
    return ret;
}
int L[maxn],R[maxn];
struct node{
    int abty;
    int loty;
    int id;
    bool operator < (const node &cmp) const{
        return abty>cmp.abty;
    }
}in[maxn];
int ans[maxn];
struct EDGE{
	int v,next;
}edge[maxn*2];
int head[maxn];
int E;
int tot;
void add(int a,int b)
{
	edge[E].v=b;
	edge[E].next=head[a];
	head[a]=E++;
}
stack<int> ss;
bool vis[maxn];
void dfs(int root)   {
	tot=0;
	while(!ss.empty()) ss.pop();
	ss.push(root);
	memset(vis,false,sizeof(vis));
    while(!ss.empty())
	{
		int now=ss.top();
		if(!vis[now])
		{
			L[now]=tot++;
			vis[now]=true;
		}
		bool flag=false;
		for(int i=head[now];i!=-1;i=edge[i].next)
		{
			if(!vis[edge[i].v])
			{
				flag=true;
				ss.push(edge[i].v);
				head[now]=edge[i].next;
				break;
			}
		}
		if(flag) continue;
		if(vis[now])
		{
			R[now]=tot;
			ss.pop();
		}
	}
}
map<int,int> mp;
int main()  {
    int t,n,m;
    scanf("%d",&t);
    while(t--)    {
        mp.clear();
        scanf("%d%d",&n,&m);
        fill(head,head+n+1,-1);E=0;
        for(int i=1,fa;i<n;i++)    {
            scanf("%d%d%d",&fa,&in[i].loty,&in[i].abty);
            add(fa,i);
            in[i].id=i;
            mp[in[i].loty]=i;
        }
        sort(in+1,in+n);
        dfs(0);
        build(0,tot-1,1);
        memset(ans,-1,sizeof(ans));
        for(int i=1,j;i<n;i=j)    {
            j=i;
            while(j<n && in[j].abty==in[i].abty)    {
                int id=in[j].id;
                int lo=query(L[id]+1,R[id]-1,0,tot-1,1);
                ans[id]=  lo==-1 ? -1 :mp[lo];
                j++;
            }
            j=i;
            while(j<n && in[j].abty==in[i].abty)    {
                int id=in[j].id;
                update(L[id],id,in[j].loty,0,tot-1,1);
                j++;
            }
        }
        int u;
        while(m--)    {
            scanf("%d",&u);
            printf("%d\n",ans[u]);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值