zoukankan      html  css  js  c++  java
  • BZOJ2588: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),表示一组询问。

    Output

    M行,表示每个询问的答案。最后一个询问不输出换行符

    Sample Input

    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

    Sample Output

    2
    8
    9
    105
    7

    HINT

    HINT:
    N,M<=100000
    暴力自重。。。

    Solution

    emmmLCA求错了然后debug了1h的丢人事迹我是不会说的
    一开始看到这个题以为是点分,然后发现没法做。
    现在做主席树的时候做到这个题了
    就想在DFS序上搞事情……就像链剖一样……然后GG了
    偷看了一眼题解的第一行发现用Root[i]表示路径[1,i]情况
    然后就没什么思维难度了……
    对于路径[u,v]的离散化后的值域情况
    我们可以用segt[v]+segt[u]-segt[lca]-segt[father[lca]]来计算
    然后就是求第k大的模板了
    建树的时候有点小技巧(见代码)

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #define N (100000+100)
      6 using namespace std;
      7 struct node{int sum,lson,rson;}Segt[N*40];
      8 struct node1{int to,next;}edge[N*2];
      9 int a[N],b[N],n,m,Root[N],segt_num,u,v,x,y,k,num,lastans;
     10 int head[N],num_edge,Father[N],f[N][20],Depth[N];
     11 
     12 void add(int u,int v)
     13 {
     14     edge[++num_edge].to=v;
     15     edge[num_edge].next=head[u];
     16     head[u]=num_edge;
     17 }
     18 
     19 int Build(int l,int r)
     20 {
     21     int node=++segt_num;
     22     if (l==r) return node;
     23     int mid=(l+r)>>1;
     24     Segt[node].lson=Build(l,mid);
     25     Segt[node].rson=Build(mid+1,r); 
     26     return node;
     27 }
     28 
     29 int Update(int pre,int l,int r,int x)
     30 {
     31     int node=++segt_num;
     32     Segt[node].sum=Segt[pre].sum+1;
     33     Segt[node].lson=Segt[pre].lson;
     34     Segt[node].rson=Segt[pre].rson;
     35     if (l==r) return node;
     36     int mid=(l+r)>>1;
     37     if (x<=mid) Segt[node].lson=Update(Segt[node].lson,l,mid,x);
     38     else Segt[node].rson=Update(Segt[node].rson,mid+1,r,x);
     39     return node;
     40 }
     41 
     42 void Dfs1(int x)
     43 {
     44     Depth[x]=Depth[Father[x]]+1;
     45     for (int i=head[x];i;i=edge[i].next)
     46         if (edge[i].to!=Father[x])
     47         {
     48             Father[edge[i].to]=f[edge[i].to][0]=x;
     49             Dfs1(edge[i].to);
     50         }
     51 }
     52 
     53 void Dfs2(int x)
     54 {
     55     int t=lower_bound(b+1,b+num+1,a[x])-b;
     56     Root[x]=Update(Root[Father[x]],1,num,t);//因为这里父亲的主席树已经建立好了,所以这个点的主席树就可以建立了 
     57     for (int i=head[x];i;i=edge[i].next)
     58         if (edge[i].to!=Father[x])
     59             Dfs2(edge[i].to);
     60 }
     61 
     62 int Query(int u,int v,int lca,int flca,int l,int r,int k)
     63 {
     64     if (l==r) return b[l];
     65     int mid=(l+r)>>1,x=Segt[Segt[u].lson].sum+Segt[Segt[v].lson].sum-Segt[Segt[lca].lson].sum-Segt[Segt[flca].lson].sum;
     66     if (k<=x) return Query(Segt[u].lson,Segt[v].lson,Segt[lca].lson,Segt[flca].lson,l,mid,k);
     67     else return Query(Segt[u].rson,Segt[v].rson,Segt[lca].rson,Segt[flca].rson,mid+1,r,k-x);
     68 }
     69 
     70 int LCA(int x,int y)
     71 {
     72     if (Depth[x]<Depth[y]) swap(x,y);
     73     for (int i=18;i>=0;--i)
     74         if (Depth[f[x][i]]>=Depth[y])
     75             x=f[x][i];
     76     if (x==y) return y;
     77     for (int i=18;i>=0;--i)
     78         if (f[x][i]!=f[y][i])
     79             x=f[x][i],y=f[y][i];
     80     return Father[x];
     81 }
     82 
     83 int main()
     84 {
     85     scanf("%d%d",&n,&m);
     86     for (int i=1;i<=n;++i)
     87         scanf("%d",&a[i]),b[i]=a[i];
     88     sort(b+1,b+n+1);
     89     num=unique(b+1,b+n+1)-b-1;
     90     Root[0]=Build(1,num);//多一个0点方便处理,作为1的父亲 
     91     add(0,1); add(1,0);
     92     for (int i=1;i<=n-1;++i)
     93     {
     94         scanf("%d%d",&u,&v);
     95         add(u,v); add(v,u);
     96     }
     97     Dfs1(0);//以1为根建树 
     98     for (int i=1;i<=18;++i)
     99         for (int j=1;j<=n;++j)
    100             f[j][i]=f[f[j][i-1]][i-1];
    101     Dfs2(1);//建立主席树 
    102     for (int i=1;i<=m;++i)
    103     {
    104         scanf("%d%d%d",&x,&y,&k);
    105         x^=lastans;
    106         int lca=LCA(x,y);
    107         printf("%d
    ",lastans=Query(Root[x],Root[y],Root[lca],Root[Father[lca]],1,num,k));
    108     } 
    109 }
  • 相关阅读:
    黑马程序员——用函数实现模块化程序设计(一)
    RN个人笔记SectionListView
    小程序实现APP底部(TabBar)页面控制效果
    #import "项目名-Swift.h"的介绍
    OC & Swift中UITextFiled、UITextView限制输入字数
    Xcode8使用CoreData如何生成OC和Swift版的SubClass
    Swift之“闭包”的应用
    Swift中两种桥接头文件创建方式
    swift头部无线轮播视图
    swift中collectionView的简单用法
  • 原文地址:https://www.cnblogs.com/refun/p/8685692.html
Copyright © 2011-2022 走看看