HDU 3804 Query on a tree (树链剖分+离线处理)

Query on a tree

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1303    Accepted Submission(s): 334


Problem Description
  There are some queries on a tree which has n nodes. Every query is described as two integers (X, Y).For each query, you should find the maximum weight of the edges in set E, which satisfies the following two conditions.
1) The edge must on the path from node X to node 1.
2) The edge’s weight should be lower or equal to Y.
  Now give you the tree and queries. Can you find out the answer for each query?
 

Input
  The first line of the input is an integer T, indicating the number of test cases. For each case, the first line contains an integer n indicates the number of nodes in the tree. Then n-1 lines follows, each line contains three integers X, Y, W indicate an edge between node X and node Y whose value is W. Then one line has one integer Q indicates the number of queries. In the next Q lines, each line contains two integers X and Y as said above.
 

Output
  For each test case, you should output Q lines. If no edge satisfy the conditions described above,just output “-1” for this query. Otherwise output the answer for this query.
 

Sample Input
 
 
1 3 1 2 7 2 3 5 4 3 10 3 7 3 6 3 4
 

Sample Output
 
 
7 7 5 -1
Hint
2<=n<=10^5 2<=Q<=10^5 1<=W,Y<=10^9 The data is guaranteed that your program will overflow if you use recursion.

 




题意:
给你一棵树,和树上边的权值,在有q组询问a,b,问你从节点a->节点1的路径上,不小于b的最大的边的权值是多少,输出

解析:
一开始想到区间第k大的数问题上,用归并树做会MLE,所以就搜了题解
题解写的是一开始建一颗空树,然后记录每条边的权值,并按权值从小到大排序,先放在数组里,再记录所有的询问,每一个询问按照b值从小到大排序,
再每一次处理,就把<=b的边插入到线段树里面,在用树链剖分进行查询得到最大值
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int MAXN = 1e5+10;
typedef long long int lli;
#define INF 0x3f3f3f3f3f3f3f3f
#define M(a) memset(a,0,sizeof(a))
#define lson root<<1
#define rson root<<1|1
int fa[MAXN],dep[MAXN],siz[MAXN],id[MAXN],top[MAXN],ran[MAXN],son[MAXN];

typedef struct fc
{
    int id;
    lli w;
}fc;

fc val[MAXN];

typedef struct ee
{
    int u,v;
    int next;
    lli w;
}ee;

ee edge[MAXN*2];
int head[MAXN],cnt;
int num,n;

typedef struct node
{
    int l,r;
    int val;
}node;

node Btree[MAXN*4];

lli d[MAXN*50];
int tot;

void addedge(int u,int v,lli cap)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    edge[cnt].w=cap;
    head[u]=cnt++;
}

void dfs1(int x,int f,int d)
{
    dep[x]=d;
    siz[x]=1;
    son[x]=0;
    fa[x]=f;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int tmp=edge[i].v;
        if(tmp==f) continue;
        dfs1(tmp,x,d+1);
        siz[x]+=siz[tmp];
        if(siz[son[x]]<siz[tmp])
        {
            son[x]=tmp;
        }
    }
}

void dfs2(int x,int tp)
{
    top[x]=tp;
    id[x]=++num;
    ran[num]=x;
    if(son[x]) dfs2(son[x],tp);
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int tmp=edge[i].v;
        if(tmp==fa[x]||tmp==son[x]) continue;
        dfs2(tmp,tmp);
    }

}


void build(int l,int r,int root)
{
    if(l>r) return;
    if(l==r)
    {
        Btree[root].l=l;
        Btree[root].r=r;
        Btree[root].val=0;
        return;
    }

    int mid=(l+r)/2;
    build(l,mid,root*2);
    build(mid+1,r,root*2+1);

    Btree[root].l=l;
    Btree[root].r=r;
    Btree[root].val=max(Btree[lson].val,Btree[rson].val);




}

void update(int root,int l,int r,int index,int val)
{
    if(l>r) return;
    if(l==r)
    {
        if(l==index)
        {
            Btree[root].val=val;
        }
        return;

    }

    int mid=(l+r)/2;
    if(index<=mid)
        update(root*2,l,mid,index,val);
    else
        update(root*2+1,mid+1,r,index,val);

    Btree[root].val=max(Btree[lson].val,Btree[rson].val);
}

lli querysum(int root,int l,int r,int s,int e)
{
    if(r<s||l>e)
    {
        return 0;
    }
    if(l>r) return 0;
    if(s<=l&&r<=e)
    {
        return Btree[root].val;
    }
    int mid=(l+r)/2;

    if(mid>=e) return querysum(2*root,l,mid,s,e);
    else if(mid+1<=s) return querysum(root*2+1,mid+1,r,s,e);
    else
    {
        return max(querysum(2*root,l,mid,s,e),querysum(root*2+1,mid+1,r,s,e));
    }

}
/*********************前面就是简单的线段树求最大值的部分******/
lli solvesum(int a,int b,lli c)
{
    if(dep[top[a]]<dep[top[b]])
    {
        swap(a,b);
    }
    lli ans=0;
    while(top[a]!=top[b])
    {
        //int tmp=top[a];
        ans=max(ans,querysum(1,1,n,id[top[a]],id[a]));
        a=fa[top[a]];
        if(dep[top[a]]<dep[top[b]])
        {
            swap(a,b);
        }
    }
    if(id[a]>id[b]) swap(a,b);
    ans=max(ans,querysum(1,1,n,id[a],id[b]));
    if(ans==0) return -1;
    else
    return ans;
}


bool cmp1(fc a,fc b)
{
    if(a.w==b.w) return a.id<b.id;
    return a.w<b.w;
}

typedef struct qu
{
    int ind;
    lli w;
    int id;
    lli ans;
}qu;
qu ques[MAXN];

bool cmp2(qu a,qu b)
{
    return a.w<b.w;
}

bool cmp3(qu a,qu b)
{
    return a.id<b.id;
}

int main()
{
    int q,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        num=tot=0;
        M(Btree);
        M(son);
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++)
        {
            int u,v;
            lli w;
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }

        dfs1(1,0,1);
        dfs2(1,1);
        for(int i=0;i<cnt;i+=2)
        {
            if(dep[edge[i].u]>dep[edge[i].v]) swap(edge[i].u,edge[i].v);
            val[id[edge[i].v]].w=edge[i].w;
            val[id[edge[i].v]].id=id[edge[i].v];
        }
        sort(val+2,val+n+1,cmp1);
        int cm,a,b;
        build(1,n,1);
        scanf("%d",&q);
        cm=2;
        for(int i=0;i<q;i++)
        {
            scanf("%d%lld",&ques[i].ind,&ques[i].w);
            ques[i].id=i;
        }
        sort(ques,ques+q,cmp2);
        for(int i=0;i<q;i++)
        {
            int a=ques[i].ind;
            lli b=ques[i].w;
            while(val[cm].w<=b)
            {
                update(1,1,n,val[cm].id,val[cm].w);
                cm++;
            }
            ques[i].ans=solvesum(a,1,b+1);
        }
        sort(ques,ques+q,cmp3);
        for(int i=0;i<q;i++)
        {
            printf("%lld\n",ques[i].ans);
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值