题目大意
给你一棵有n个结点的树,节点编号为1~n。每个节点都有一个权值。要求执行以下操作:
U V K:求从节点u到节点v的第k小权值
题解
这不是道主席树裸题吗,其实就是要询问四颗权值线段树,u,v,lca(u,v),fa(lca(u,v)),lca树上倍增都会吧。虽说好象真的挺简单的,但是因为懒,不想对拍,肉查了好久,不过最后还是成功,几乎放弃时,Arrival to Earth激励了我,所以不管怎样都别放弃,朋友。
code
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for (int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int M=100000+5;
int g[M][21],next[M*2],head[M],to[M*2],rt[4001000],s[4001000],ls[4001000],rs[ 4001000];
int h[M],val[M],v,d[M],cd,tot,cnt;
void R(int &n)
{
int t=0,p=1;char ch;
for(ch=getchar ();!('0'<=ch && ch<='9');ch=getchar())
if(ch=='-') p=-1;
for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
n=t*p;
}
void add(int x,int y)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void ch(int x,int &y,int l,int r,int v)
{
s[y=++cnt]=s[x]+1;
if (l==r) return ;
int m=l+r>>1;
if (v<=m)
{
rs[y]=rs[x];
ch(ls[x],ls[y],l,m,v);
}
else
{
ls[y]=ls[x];
ch(rs[x],rs[y],m+1,r,v);
}
}
int query(int x,int y,int z,int w,int l,int r,int k)
{
if (l==r) return l;
int tmp=s[ls[y]]+s[ls[z]]-s[ls[x]]-s[ls[w]];
int m=l+r>>1;
if (tmp>=k) return query(ls[x],ls[y],ls[z],ls[w],l,m,k);
else return query(rs[x],rs[y],rs[z],rs[w],m+1,r,k-tmp);
}
void dfs(int x,int y)
{
for (int i=head[x];i;i=next[i])
{
v=to[i];
if (y!=v)
{
d[v]=d[x]+1;
g[v][0]=x;
ch(rt[x],rt[v],1,cd,val[v]);
dfs(v,x);
}
}
}
int lca(int x,int y)
{
if (d[x]<d[y]) swap(x,y);
fd(k,20,0)
if (d[g[x][k]]>d[y]) x=g[x][k];
if (d[x]!=d[y]) x=g[x][0];
fd(k,20,0)
if (g[x][k]!=g[y][k])
x=g[x][k],y=g[y][k];
if (x!=y) return g[x][0];
else return x;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int n,m,x,y,z,k;
R(n);R(m);
fo(i,1,n)R(val[i]),h[i]=val[i];
sort(h+1,h+1+n);
cd=unique(h+1,h+1+n)-(h+1);
fo(i,1,n)val[i]=lower_bound(h+1,h+1+cd,val[i])-h;
fo(i,1,n-1)
{
R(x);R(y);
add(x,y);add(y,x);
}
ch(rt[0],rt[1],1,cd,val[1]);
d[1]=1;
dfs(1,0);
fo(j,1,20)
fo(i,1,n)
g[i][j]=g[g[i][j-1]][j-1];
g[1][0]=0;
int ans=0;
while (m--)
{
R(x);R(y);R(k);
z=lca(x,y);
ans=h[query(rt[z],rt[x],rt[y],rt[g[z][0]],1,cd,k)];
printf("%d\n",ans);
}
return 0;
}
感觉打得好丑,还请各位笑纳。