SPOJ 10628. Count on a tree

10628. Count on a tree

Problem code: COT


You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

We will ask you to perform the following operation:

  • u v k : ask for the kth minimum weight on the path from node u to node v

 

Input

In the first line there are two integers N and M.(N,M<=100000)

In the second line there are N integers.The ith integer denotes the weight of the ith node.

In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.

Output

For each operation,print its result.

Example

Input:

 
 
8 5
8 5 105 2 9 3 8 5 7 7 1 2 1 3 1 4 3 5 3 6 3 7 4 8 2 5 1 2 5 2 2 5 3 2 5 4 7 8 2 
Output:
2
8
9
105

求x到y路径上第k小的数,无修改。利用函数式线段树,可以把x到y的路径表示出来,也就是root[x]-root[fa[lca][0]]+root[y]-root[lca],lca是x,y的最近公共祖先,fa[lca][0]是lca的父亲。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <stdlib.h>
#include <algorithm>
using namespace std;

typedef long long ll;
#define rep(i,s,t) for(int i=s;i<t;i++)
#define red(i,s,t) for(int i=s-1;i>=t;i--)
#define ree(i,now) for(int i=head[now];i!=-1;i=edge[i].next)
#define clr(a,v) memset(a,v,sizeof a)
#define MID(x,y) int mid=(x+y)>>1

inline int input(){
    int ret=0;bool isN=0;char c=getchar();
    while(c<'0' || c>'9'){
        if(c=='-') isN=1;
        c=getchar();
    }
    while(c>='0' && c<='9'){
        ret=ret*10+c-'0';
        c=getchar();
    }
    return isN?-ret:ret;
}

inline void output(int x){
    if(x<0){
        putchar('-');x=-x;
    }
    int len=0,data[11];
    while(x){
        data[len++]=x%10;x/=10;
    }
    if(!len)    data[len++]=0;
    while(len--)
        putchar(data[len]+48);
    putchar('\n');
}

const int N=100005;
const int M=5000005;
int n,m,u,v,k,w[N];
int e,head[N];
int fa[N][20],dep[N];
struct EDGE{
    int v,next;
}edge[N<<1];

inline void addEdge(int u,int v){
    edge[e].v=v;
    edge[e].next=head[u];
    head[u]=e++;
}

int root[N];
int tot,s[M],ls[M],rs[M];
int y[N],cnt;

inline void copy(int k,int p){
        s[k]=s[p];ls[k]=ls[p];rs[k]=rs[p];
}

inline int build(int x,int y){
    int k=(++tot);
    s[k]=0;
    if(x!=y){
        MID(x,y);
        ls[k]=build(x,mid);
        rs[k]=build(mid+1,y);
    }
    return k;
}

inline int add(int p,int l,int r,int x){
    int k=(++tot);copy(k,p);
    s[k]++;
    if(l==r) return k;
    MID(l,r);
    if(x<=mid) ls[k]=add(ls[p],l,mid,x);
    else rs[k]=add(rs[p],mid+1,r,x);
    return k;
}

inline int query(int a,int b,int lca,int f,int l,int r,int k){
    if(l==r) return l;
    int t=s[ls[a]]-s[ls[f]]+s[ls[b]]-s[ls[lca]];
    MID(l,r);
    if(t>=k) return query(ls[a],ls[b],ls[lca],ls[f],l,mid,k);
    else return query(rs[a],rs[b],rs[lca],rs[f],mid+1,r,k-t);
}

inline void dfs(int now,int pre){
    dep[now]=dep[pre]+1;
    fa[now][0]=pre;
    rep(i,1,20) fa[now][i]=fa[fa[now][i-1]][i-1];
    root[now]=add(root[pre],1,cnt,w[now]);
    ree(i,now){
        if(edge[i].v!=pre) dfs(edge[i].v,now);
    }
}

inline int LCA(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    int delta=dep[y]-dep[x];
    rep(i,0,20){
        if(delta & (1<<i)) y=fa[y][i];
    }
    if(x==y) return x;
    red(i,20,0){
        if(fa[x][i]==fa[y][i]) continue;
        x=fa[x][i];
        y=fa[y][i];
    }
    return fa[x][0];
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        clr(head,-1),e=cnt=0;
        rep(i,1,n+1){
            w[i]=input();
            y[++cnt]=w[i];
        }
        sort(y+1,y+1+cnt);
        cnt=unique(y+1,y+1+cnt)-(y+1);
        rep(i,1,n+1) w[i]=lower_bound(y+1,y+cnt+1,w[i])-(y+1)+1;
        rep(i,1,n){
            u=input(),v=input();
            addEdge(u,v);addEdge(v,u);
        }
        fa[0][0]=dep[0]=0;tot=0;
        root[0]=build(1,cnt);
        dfs(1,0);
        rep(i,0,m){
            u=input(),v=input(),k=input();
            int lca=LCA(u,v);
            int f=fa[lca][0];
            //cout<<u << " "<< v<< " "<< lca<< " "<<f<<endl;
            output(y[query(root[u],root[v],root[lca],root[f],1,cnt,k)]);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
洛谷的SPOJ需要注册一个SPOJ账号并进行绑定才能进行交题。您可以按照以下步骤进行注册: 1. 打开洛谷网站(https://www.luogu.com.cn/)并登录您的洛谷账号。 2. 在网站顶部导航栏中找到“题库”选项,将鼠标悬停在上面,然后选择“SPOJ”。 3. 在SPOJ页面上,您会看到一个提示,要求您注册SPOJ账号并进行绑定。点击提示中的链接,将会跳转到SPOJ注册页面。 4. 在SPOJ注册页面上,按照要求填写您的用户名、密码和邮箱等信息,并完成注册。 5. 注册完成后,返回洛谷网站,再次进入SPOJ页面。您会看到一个输入框,要求您输入刚刚注册的SPOJ用户名。输入用户名后,点击“绑定”按钮即可完成绑定。 现在您已经成功注册并绑定了SPOJ账号,可以开始在洛谷的SPOJ题库上刷题了。祝您顺利完成编程练习!\[1\]\[2\] #### 引用[.reference_title] - *1* *3* [(洛谷入门系列,适合洛谷新用户)洛谷功能全解](https://blog.csdn.net/rrc12345/article/details/122500057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [luogu p7492 序列](https://blog.csdn.net/zhu_yin233/article/details/122051384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值