bzoj2588 Spoj10628. count on a tree

题目描述

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

输入输出格式

输入格式:

 

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

 

输出格式:

 

M行,表示每个询问的答案。

 

输入输出样例

输入样例#1:
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
0 5 2
10 5 3
11 5 4
110 8 2
输出样例#1:
2
8
9
105
7

说明

HINT:

N,M<=100000

暴力自重。。。

 

题解

其实就是个很简单的主席树,只要把在序列上的建树改成在树上建就可以了

虽然我也是今天看到这道题看完题解才知道怎么在树上建主席树

关于路径,可以在树上差分一下用$sum[l]+sum[r]-sum[lca]-sum[lca_fa]$

然后因为要求lca,所以在树剖dfs的时候顺便建一下主席树就好了

具体实现请参考代码

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define N 100005
 4 #define M 2000005
 5 using namespace std;
 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 7 char buf[1<<21],*p1=buf,*p2=buf;
 8 inline int read(){
 9     #define num ch-'0'
10     char ch;bool flag=0;int res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 int sum[M],L[M],R[M];
19 int a[N],b[N],rt[N];
20 int fa[N],sz[N],d[N],ver[N<<1],Next[N<<1],head[N],son[N],top[N];
21 int n,q,m,cnt=0,tot=0,ans=0;
22 void update(int last,int &now,int l,int r,int x){
23     sum[now=++cnt]=sum[last]+1;
24     if(l==r) return;
25     int mid=(l+r)>>1;
26     if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
27     else L[now]=L[last],update(R[last],R[now],mid+1,r,x);
28 }
29 inline void add(int u,int v){
30     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
31     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
32 }
33 void dfs(int u){
34     sz[u]=1,d[u]=d[fa[u]]+1;
35     update(rt[fa[u]],rt[u],1,m,a[u]);
36     for(int i=head[u];i;i=Next[i]){
37         int v=ver[i];
38         if(v==fa[u]) continue;
39         fa[v]=u,dfs(v);
40         sz[u]+=sz[v];
41         if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
42     }
43 }
44 void dfs(int u,int tp){
45     top[u]=tp;
46     if(!son[u]) return;
47     dfs(son[u],tp);
48     for(int i=head[u];i;i=Next[i]){
49         int v=ver[i];
50         if(v==son[u]||v==fa[u]) continue;
51         dfs(v,v);
52     }
53 }
54 int LCA(int x,int y){
55     while(top[x]!=top[y])
56     d[top[x]]>=d[top[y]]?x=fa[top[x]]:y=fa[top[y]];
57     return d[x]>=d[y]?y:x;
58 }
59 int query(int ql,int qr,int lca,int lca_fa,int l,int r,int k){
60     if(l>=r) return l;
61     int x=sum[L[ql]]+sum[L[qr]]-sum[L[lca]]-sum[L[lca_fa]];
62     int mid=(l+r)>>1;
63     if(x>=k) return query(L[ql],L[qr],L[lca],L[lca_fa],l,mid,k);
64     else return query(R[ql],R[qr],R[lca],R[lca_fa],mid+1,r,k-x);
65 }
66 int main(){
67     //freopen("testdata.in","r",stdin);
68     n=read(),q=read();
69     for(int i=1;i<=n;++i)
70     b[i]=a[i]=read();
71     sort(b+1,b+1+n);
72     m=unique(b+1,b+1+n)-b-1;
73     for(int i=1;i<=n;++i)
74     a[i]=lower_bound(b+1,b+1+m,a[i])-b;
75     for(int i=1;i<n;++i){
76         int u=read(),v=read();
77         add(u,v);
78     }
79     dfs(1),dfs(1,1);
80     while(q--){
81         int x,y,z,lca;
82         x=read(),y=read(),z=read();
83         x^=ans,lca=LCA(x,y);
84         ans=b[query(rt[x],rt[y],rt[lca],rt[fa[lca]],1,m,z)];
85         printf("%d\n",ans);
86     }
87     return 0;
88 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9392425.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值