hdoj 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): 934    Accepted Submission(s): 203


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.
 

题意:给定一棵n个节点的树和Q次查询,查询 x y表示1-x的路径上边权<=y的条件下最大的边权,若没有满足的边输出-1。


思路:离线做,我们把树边按权值升序排列,查询y升序排列,对于第i次查询,只需将边权<=ans[i].y的树边加进去就好了,然后就是链上的区间求最大值。


AC代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (100000+10)
#define MAXM (300000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while((a)--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
#pragma comment(linker, "/STACK:102400000,102400000")
#define fi first
#define se second
using namespace std;
struct Tree{
    int l, r, Max;
};
Tree tree[MAXN<<2];
void PushUp(int o){
    tree[o].Max = max(tree[ll].Max, tree[rr].Max);
}
void Build(int o, int l, int r)
{
    tree[o].l = l; tree[o].r = r;
    tree[o].Max = -1;
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    Build(lson); Build(rson);
}
void Update(int o, int pos, int v)
{
    if(tree[o].l == tree[o].r)
    {
        tree[o].Max = v;
        return ;
    }
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(pos <= mid) Update(ll, pos, v);
    else Update(rr, pos, v);
    PushUp(o);
}
int Query(int o, int L, int R)
{
    if(tree[o].l == L && tree[o].r == R)
        return tree[o].Max;
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) return Query(ll, L, R);
    else if(L > mid) return Query(rr, L, R);
    else return max(Query(ll, L, mid), Query(rr, mid+1, R));
}
struct Edge{
    int from, to, next;
};
Edge edge[MAXN<<1];
int head[MAXN], edgenum;
void init(){
    edgenum = 0; CLR(head, -1);
}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
int son[MAXN], num[MAXN];
int top[MAXN], pos[MAXN], id;
int dep[MAXN], pre[MAXN];
void DFS1(int u, int fa, int d)
{
    dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == fa) continue;
        DFS1(v, u, d+1);
        num[u] += num[v];
        if(son[u] == -1 || num[son[u]] < num[v])
            son[u] = v;
    }
}
void DFS2(int u, int T)
{
    top[u] = T; pos[u] = ++id;
    if(son[u] == -1) return ;
    DFS2(son[u], T);
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre[u] || v == son[u]) continue;
        DFS2(v, v);
    }
}
int GetMax(int u, int v)
{
    int f1 = top[u], f2 = top[v];
    int ans = -1;
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(u, v);
            swap(f1, f2);
        }
        ans = max(ans, Query(1, pos[f1], pos[u]));
        u = pre[f1], f1 = top[u];
    }
    if(u == v) return ans;
    if(dep[u] > dep[v]) swap(u, v);
    return max(ans, Query(1, pos[son[u]], pos[v]));
}
struct Node{
    int s, e, c;
};
Node In[MAXN];
bool cmp1(Node a, Node b){
    return a.c < b.c;
}
struct Ans{
    int x, y, id, res;
};
Ans ans[MAXN];
bool cmp2(Ans a, Ans b){
    return a.y < b.y;
}
bool cmp3(Ans a, Ans b){
    return a.id < b.id;
}
int main()
{
    int t; Ri(t);
    W(t)
    {
        int n; Ri(n); init();
        for(int i = 1; i <= n-1; i++)
        {
            Ri(In[i].s); Ri(In[i].e); Ri(In[i].c);
            addEdge(In[i].s, In[i].e);
            addEdge(In[i].e, In[i].s);
        }
        DFS1(1, -1, 1); id = 0; DFS2(1, 1); Build(1, 1, id);
        sort(In+1, In+n, cmp1);
        for(int i = 1; i <= n-1; i++) if(dep[In[i].s] > dep[In[i].e]) swap(In[i].s, In[i].e);
        int Q; Ri(Q);
        for(int i = 1; i <= Q; i++)
            Ri(ans[i].x), Ri(ans[i].y), ans[i].id = i;
        sort(ans+1, ans+Q+1, cmp2); int j = 1;
        for(int i = 1; i <= Q; i++)
        {
            while(In[j].c <= ans[i].y && j <= n-1) {Update(1, pos[In[j].e], In[j].c); j++;}
            ans[i].res = GetMax(1, ans[i].x);
        }
        sort(ans+1, ans+Q+1, cmp3);
        for(int i = 1; i <= Q; i++) Pi(ans[i].res);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值