spoj10628- Count on a tree

题目大意

给你一棵有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;
}

感觉打得好丑,还请各位笑纳。

猜你喜欢

转载自blog.csdn.net/ganjingxian/article/details/80627778