zoukankan      html  css  js  c++  java
  • 洛谷P2633/bzoj2588 Count on a tree (主席树)

    洛谷P2633/bzoj2588 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

    暴力自重。。。

    来源:bzoj2588 Spoj10628.

    Solution

    bzoj题面传送门
    无修改,树上路径查询k小值

    k小值可以主席树解决,树上路径其实不用真的提出来,我们可以运用差分的思路,由于是点差,求出它的(lca,)那么(ans=a[u]+a[v]-a[lca]-a[fa[lca]]).

    具体到这道题就是(u)的主席树(+v)的主席树(-lca)的主席树(-fa[lca])的主席树

    (lca)倍增求就可以了

    Code

    #include<bits/stdc++.h>
    #define in(i) (i=read())
    #define il extern inline
    #define rg register
    #define mid ((l+r)>>1)
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define lol long long
    using namespace std;
    
    const int N=1e5+10;
    
    int read() {
        int ans=0, f=1; char i=getchar();
        while (i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
        while (i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48), i=getchar();
        return ans*f;
    }
    
    int n,m,cur,num,tot,pre;
    int head[N],nex[N<<1],to[N<<1];
    int f[25][N],lg[N]={-1},dep[N];
    int a[N],h[N],rt[N<<6];
    
    struct Chair_Tree {
        int l,r,v;
    }t[N<<6];
    
    void add(int a,int b) {
        to[++cur]=b,nex[cur]=head[a],head[a]=cur;
        to[++cur]=a,nex[cur]=head[b],head[b]=cur;
    }
    
    void insert(int &u,int l,int r,int pre,int p) {
        t[u=++tot]=t[pre], t[u].v++;
        if(l==r) return;
        if(p<=mid) insert(t[u].l,l,mid,t[pre].l,p);
        else insert(t[u].r,mid+1,r,t[pre].r,p);
    }
    
    int query(int a,int b,int c,int d,int l,int r,int k) {
        int AQ=t[t[a].l].v+t[t[b].l].v-t[t[c].l].v-t[t[d].l].v;
        if(l==r) return h[l];
        if(k<=AQ) return query(t[a].l,t[b].l,t[c].l,t[d].l,l,mid,k);
        else return query(t[a].r,t[b].r,t[c].r,t[d].r,mid+1,r,k-AQ);
    }
    
    void dfs(int u) {
        a[u]=lower_bound(h+1,h+1+num,a[u])-h;
        insert(rt[u],1,num,rt[f[0][u]],a[u]);
        for (int i=head[u];i;i=nex[i]) {
            if(to[i]==f[0][u]) continue;
            dep[to[i]]=dep[u]+1, f[0][to[i]]=u;
            dfs(to[i]);
        }
    }
    
    void init() {
        for (int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
        for (int i=1;i<=lg[n];i++)
            for (int j=1;j<=n;j++)
                f[i][j]=f[i-1][f[i-1][j]];
    }
    
    int LCA(int a,int b) {
        if(dep[a]>dep[b]) swap(a,b);
        int s=dep[b]-dep[a];
        for (int i=lg[s];i>=0;i--)
            if(s>>i&1) b=f[i][b];
        if(a==b) return a;
        for (int i=lg[n];i>=0;i--) {
            if(f[i][a]==f[i][b]) continue;
            a=f[i][a], b=f[i][b];
        }return f[0][a];
    }
    
    int main()
    {
        in(n), in(m);
        for (int i=1;i<=n;i++) in(a[i]),h[i]=a[i];
        sort(h+1,h+1+n); num=unique(h+1,h+1+n)-h-1;
        for (int i=1,x,y;i<n;i++) in(x),in(y),add(x,y);
        dep[1]=1, dfs(1), init();
        for (int i=1,a,b,k;i<=m;i++) {
            in(a),in(b),in(k),a^=pre;
            int lca=LCA(a,b);
            printf("%d
    ",pre=query(rt[a],rt[b],rt[lca],rt[f[0][lca]],1,num,k));
        }
    }
    
  • 相关阅读:
    数据结构与算法
    ROS 机器人技术
    我常用的 VSCode C:C++ 插件!
    Ubuntu 常用的录屏、截图、Gif 软件!
    从 0 开始机器学习
    Word 设置页码从指定页开始的详细步骤!
    Ubuntu16.04 更新 ruby-2.6!
    配置 Git 不用每次 push 都输入密码!
    解决 rubygems.org 无法访问的问题!
    PHP 反序列化漏洞入门学习笔记
  • 原文地址:https://www.cnblogs.com/real-l/p/9889850.html
Copyright © 2011-2022 走看看