hdu 4605 线段树与二叉树遍历

思路:

首先将所有的查询有一个vector保存起来。我们从1号点开始dfs这颗二叉树,用线段树记录到当前节点时,走左节点的有多少比要查询该节点的X值小的,有多少大的,

同样要记录走右节点的有多少比X小的,多少比X大的。小和大的x,y值题目给了。当要进行左儿子时,建该节点值插入走左的线段树,回退的时候将其删除,进入右儿子时将其插入走右的线段树,同样回退时删除。遍历完一个树,整个查询就做完了,最后输出。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define Maxn 200100
#define lson(x) (x<<1)
#define rson(x) ((x<<1)+1)
#define mid ((tree[po].l+tree[po].r)>>1)
#define inf 100000000
using namespace std;
struct Query{
    int x,i;
};
struct AA{
    int x,y;
}ans[Maxn];
struct Tree{
    int l,r,lnum,rnum;
}tree[Maxn*20];
int head[Maxn],e,w[Maxn],Index[Maxn],flag=0,L,R,Lsum,Rsum;
vector<Query> query[Maxn];
struct Edge{
    int u,v,next;
}edge[Maxn];
void buildTree(int l,int r,int po)
{
    tree[po].l=l,tree[po].r=r;
    tree[po].lnum=0,tree[po].rnum=0;
    if(l==r)
        return ;
    buildTree(l,mid,lson(po));
    buildTree(mid+1,r,rson(po));
}
void Insert(int val,int po,int type)
{
    if(tree[po].l==tree[po].r)
    {
        if(type)
            tree[po].rnum++;
        else
            tree[po].lnum++;
        return ;
    }
    if(type)
        tree[po].rnum++;
    else
        tree[po].lnum++;
    if(Index[mid]>=val)
        Insert(val,lson(po),type);
    else
        Insert(val,rson(po),type);
}
void del(int val,int po,int type)
{
    if(tree[po].l==tree[po].r)
    {
        if(type)
            tree[po].rnum--;
        else
            tree[po].lnum--;
        return ;
    }
    if(type)
        tree[po].rnum--;
    else
        tree[po].lnum--;
    if(Index[mid]>=val)
        del(val,lson(po),type);
    else
        del(val,rson(po),type);
}
void get_Num(int val,int po)
{
    if(Index[tree[po].l]>val)
        return ;
    if(Index[tree[po].r]<val)
    {
            R+=tree[po].rnum;
            L+=tree[po].lnum;
            return ;
    }
    if(tree[po].l==tree[po].r)
    {
        if(tree[po].rnum||tree[po].lnum)//如果图中有相同数值,则不能到达
            flag=1;
        return ;
    }
    get_Num(val,lson(po));
    get_Num(val,rson(po));
}
void init()
{
    e=0;
    Lsum=Rsum=0;
    memset(head,-1,sizeof(head));
    for(int i=0;i<=110010;i++)
     {
         query[i].clear();
         ans[i].x=ans[i].y=0;
     }
}
void add(int u,int v)
{
    edge[e].u=u;edge[e].v=v;edge[e].next=head[u];head[u]=e++;
}
void dfs(int u)//进行二叉树遍历
{
    int i,j,temp,Size,pos;
    Size=query[u].size();
    for(i=0;i<Size;i++)
    {
        L=R=flag=0;
        get_Num(query[u][i].x,1);
        if(flag)
        {
            ans[query[u][i].i].y=-1;
            continue;
        }
        ans[query[u][i].i].y+=L*3;
        ans[query[u][i].i].y+=Lsum-L;
        ans[query[u][i].i].y+=R*3;
        ans[query[u][i].i].y+=Rsum-R;
        ans[query[u][i].i].x+=R;
    }
    int f=0;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        if(f)
        {
            Insert(w[u],1,1);
            Rsum++;
        }
        else
        {
            Insert(w[u],1,0);
            Lsum++;
        }
        f++;
        dfs(edge[i].v);
        if(f==2)
        {
            del(w[u],1,1);
            Rsum--;
        }
        else
        {
            del(w[u],1,0);
            Lsum--;
        }
    }
}
int main()
{
    int n,m,q,t,i,j,a,b,u,num;
    scanf("%d",&t);
    while(t--)
    {
        init();
        num=0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
         {
            scanf("%d",w+i);
            Index[i]=w[i];
         }
        sort(Index+1,Index+n+1);
        num=1;
        for(i=2;i<=n;i++)//将坐标离散化
        if(Index[i]>Index[num])
            Index[++num]=Index[i];
        buildTree(1,num,1);//建立线段树
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&a,&b);
            add(u,b);
            add(u,a);
        }
        scanf("%d",&q);
        Query temp;
        int v;
        for(i=1;i<=q;i++)//将所有查询保存起来
        {
            scanf("%d%d",&v,&temp.x);
            temp.i=i;
            query[v].push_back(temp);
        }
        int f=0;//标记走左还是右
        for(i=head[1];i!=-1;i=edge[i].next)//从1号节点开始遍历
        {
            if(f)//若走右
            {
                Insert(w[1],1,1);//将该值插入右线段树,并且总数加1
                Rsum++;
            }
            else
            {
                Insert(w[1],1,0);//插入左线段树,总数加1
                Lsum++;
            }
                f++;
            dfs(edge[i].v);
            if(f==2)
            {
                del(w[1],1,1);//从右儿子退出,将其删除,总数减1
                Rsum--;
            }
            else
            {
                del(w[1],1,0);//从左儿子退出
                Lsum--;
            }
        }
        for(i=1;i<=q;i++)
        {
            if(ans[i].y!=-1)
                printf("%d %d\n",ans[i].x,ans[i].y);
            else
                printf("0\n");
        }
    }
    return 0;
}

 

posted @ 2013-07-24 17:13  fangguo  阅读(416)  评论(0编辑  收藏  举报