【BZOJ2588】【Spoj 10628.】 Count on a tree 可持久化线段树+lca

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/45048639");
}

题解:

对于每个树上节点存一个版本的可持久化线段树,为它到根节点上所有权值的权值线段树(需要离散化)。

然后对于每次询问,这条链(a,b)的线段树就是:线段树a+线段树b?线段树lca?线段树falca

然后线段树上求第k小啦。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define LOGN 20
#define LS s[last].l
#define RS s[last].r
#define ls s[now].l
#define rs s[now].r
using namespace std;
struct LSH
{
    int x,id;
    void read(int i){id=i;scanf("%d",&x);}
    bool operator < (const LSH &a)const
    {return x<a.x;}
}lsh[N];
int n,m,p;
struct Eli
{
    int v,next;
}e[N<<1];
int head[N],cnt,val[N];
inline void add(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
struct Segment_Tree
{
    int l,r,x;
}s[N*LOGN];
int root[N];
void add(int last,int &now,int x,int L=1,int R=p)
{
    now=++cnt;
    if(L==R)s[now].x=s[last].x+1;
    else {
        int mid=L+R>>1;
        if(x<=mid)add(LS,ls,x,L,mid),rs=RS;
        else add(RS,rs,x,mid+1,R),ls=LS;
        s[now].x=s[ls].x+s[rs].x;
    }
}
int query(int a,int b,int A,int B,int k,int L=1,int R=p)
{
    int x=s[s[a].l].x+s[s[b].l].x-s[s[A].l].x-s[s[B].l].x;
    if(L==R)return L;
    int mid=L+R>>1;
    if(k<=x)return query(s[a].l,s[b].l,s[A].l,s[B].l,k,L,mid);
    else return query(s[a].r,s[b].r,s[A].r,s[B].r,k-x,mid+1,R);
}
int fa[N][LOGN],dep[N];
void dfs(int x,int p)
{
    fa[x][0]=p;
    dep[x]=dep[p]+1;
    add(root[p],root[x],val[x]);
    int i,v;
    for(i=head[x];i;i=e[i].next)
    {
        v=e[i].v;
        if(v==p)continue;
        dfs(v,x);
    }
}
void array()
{
    for(int k=1;k<LOGN;k++)
        for(int i=1;i<=n;i++)
            fa[i][k]=fa[fa[i][k-1]][k-1];
}
int getlca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int k=LOGN-1;~k;k--)
        if(dep[fa[x][k]]>=dep[y])
            x=fa[x][k];
    if(x==y)return x;
    for(int k=LOGN-1;~k;k--)
        if(fa[x][k]!=fa[y][k])
            x=fa[x][k],y=fa[y][k];
    return fa[x][0];
}
int lastans;
int main()
{
    int i,a,b,c;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)lsh[i].read(i);
    sort(lsh+1,lsh+n+1);
    for(i=1;i<=n;i++)
    {
        if(i==1||lsh[i].x!=lsh[i-1].x)lsh[++p].x=lsh[i].x;
        val[lsh[i].id]=p;
    }
    for(cnt=0,i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    cnt=0,dfs(1,0);
    array();
    while(m--)
    {
        scanf("%d%d%d",&a,&b,&c),a^=lastans;
        i=getlca(a,b);
        a=query(root[a],root[b],root[i],root[fa[i][0]],c);
        lastans=lsh[a].x;
        printf("%d\n",lastans);
    }
    return 0;
}
时间: 2024-12-18 05:40:07

【BZOJ2588】【Spoj 10628.】 Count on a tree 可持久化线段树+lca的相关文章

BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Inp

BZOJ2588 Spoj 10628. Count on a tree

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:BZOJ2588 SPOJ10628 正解:主席树上树 解题报告: 考虑主席树上树,每次build都是儿子在父亲的基础上build,然后查询的话就是对于x到y的路径,令$Tx$为$x$对应的线段树,那就是$T_x+T_y-T_{lca}-T_{f

bzoj2588: Spoj 10628. Count on a tree(树上第k大)(主席树)

每个节点继承父节点的树,则答案为query(root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]) #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; const int maxn=100010; struct poi{int s

【主席树】bzoj2588 Spoj 10628. Count on a tree

每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using namespace std; #define N 100001 int v[N<<1],first[N],next[N<<1],en,Ans; void AddEdge(int U,int V) { v[++en]=V; next[en]=first[U]; first[U]=en;

SPOJ COT Count on a tree(树上主席树 + LCA 求路径第k小)题解

题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点u到源点1的权值线段树,那我求点u到v的所有点,显然是 u + v - lca - fa[lca],就是u到1 + v到1 - 多算的lca - 多算的fa[lca].不能减去两个lca不然少一个点了, LCA板子: //LCA int fa[maxn][20]; int dep[maxn]; vo

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问.

bzoj 2588: Spoj 10628. Count on a tree LCA+主席树

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一