HDU 4366 浅谈DFS序+线段树

来源:互联网 发布:linux 打包tar 编辑:程序博客网 时间:2024/05/21 10:30

这里写图片描述
世界真的很大
对于树上的询问要有意识地去想要不要吧树上问题转化成序列问题,就可以用线段树一类的数据结构来维护了
DFS序和树链剖分都是很不错的把树转换为序列问题的方法
看题先:
description

给一个树,树上每个节点都有两个属性:忠诚度和能力,给出若干查询,求每个子树中能力 > 树根能力的点中,忠诚度最高的那个n≤50000数值≤1000000

input

第一行一个整数T,表示数据组数每一组数据第一行两个整数n,m,表示树有n个节点,有m组操作接下来n-1行每行两个整数u,v,表示u,v之间有一条边

output:

对于每一个询问一个整数t表示答案,没有就输出-1

如果不管能力值得话,就相当于在一个数的子树里找一个忠诚度最高的,显然可以用DFS序后加以线段树解决,区间最大值而已
然后考虑怎么解决能力值得问题
仔细看来能力值并不是像忠诚度那样要求最大,只是需要大于当前查询的就行了,换句话就是说,只要能力值不比当前的大,不管是在子树外面还是里面,都对答案没有贡献,对于每一个人,有可能替代他的就只有能力值比他大的而已,再在这些人里面选一个在其子树里面忠诚度最高的
思路出来了,这个思路也是很重要的
对于两个要求条件,可以把其中一个只是范围要求的要求,排序。先建一颗空树,将能力值排序后再按忠诚度加入线段树,这样在查询任意一个人时,线段树里有的值都是比当前人能力值大的
完整代码:

#include<stdio.h>#include<cstring>#include<algorithm>using namespace std;struct edge{    int v,last;    int id,loy,aby;}ed[200010],a[100010];struct node{    int sum;    node *ls,*rs;    void update()    {        sum=max(ls->sum,rs->sum);    }}pool[2000010],*root,*tail=pool,*null;int head[200010],inv[1000010],rec[100010],in[100010],ou[100010];int idx=0,num=0,n,m,T;bool cmp(const edge &a,const edge &b){    if(a.aby==b.aby) return a.id<b.id;    return a.aby>b.aby;}void init(){    tail=pool;    null=++tail;    null->ls=null->rs=null;    null->sum=0;    idx=num=0;    memset(head,0,sizeof(head));    memset(in,0,sizeof(in));    memset(ou,0,sizeof(ou));    memset(inv,0,sizeof(inv));    memset(rec,0,sizeof(rec));}void add(int u,int v){    num++;    ed[num].v=v;    ed[num].last=head[u];    head[u]=num;}node *newnode(){    node *nd=++tail;    nd->ls=nd->rs=null;    nd->sum=-1;    return nd;}node *build(int lf,int rg){       node *nd=newnode();    if(lf==rg)        return nd;    int mid=(lf+rg)>>1;    nd->ls=build(lf,mid);    nd->rs=build(mid+1,rg);    nd->update();    return nd;}void modify(node *nd,int lf,int rg,int pos,int delta){    if(lf==rg)    {        nd->sum=delta;        return ;    }    int mid=(lf+rg)>>1;    if(pos<=mid) modify(nd->ls,lf,mid,pos,delta);    else modify(nd->rs,mid+1,rg,pos,delta);    nd->update();    return ;}int query(node *nd,int lf,int rg,int L,int R){    if(L<=lf&&rg<=R)        return nd->sum;    int mid=(lf+rg)>>1,rt=-1;    if(L<=mid) rt=max(rt,query(nd->ls,lf,mid,L,R));    if(R>mid) rt=max(rt,query(nd->rs,mid+1,rg,L,R));    return rt;}void dfs(int u,int fa){    in[u]=++idx;    for(int i=head[u];i;i=ed[i].last)    {        int v=ed[i].v;        if(v==fa) continue ;        dfs(v,u);    }    ou[u]=idx;}int main(){    scanf("%d",&T);    while(T--)    {        int v;        init();        scanf("%d%d",&n,&m);        for(int i=1;i<n;i++)        {            scanf("%d%d%d",&v,&a[i].loy,&a[i].aby),a[i].id=i,inv[a[i].loy]=i;            add(i,v),add(v,i);        }        dfs(0,0);        root=build(1,idx);        sort(a+1,a+n,cmp);        for(int i=1;i<n;i++)        {            int x=a[i].id;            rec[x]=query(root,1,idx,in[x],ou[x]);            if(rec[x]!=-1) rec[x]=inv[rec[x]];            modify(root,1,idx,in[x],a[i].loy);        }        while(m--)        {            scanf("%d",&v);            printf("%d\n",rec[v]);        }    }    return 0;}/*Whoso pulleth out this sword from this stone and anvil is duly born King of all England*/

嗯,就是这样

原创粉丝点击