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


    分析:树上第k小,然后我想说的是主席树并不局限于线性表

            详细分析请看http://www.cnblogs.com/rausen/p/4006116.html,讲的很好,

            然后因为这个熟悉了主席树,真是神器,强制在线,然后顺便学习了LCA倍增算法

           LCA倍增算法是O(nlogn)预处理,然后O(logn)查询,其实和ST是一样的,但是好写啊

        

    /**************************************************************
        Problem: 2588
        User: 96655
        Language: C++
        Result: Accepted
        Time:4792 ms
        Memory:47884 kb
    ****************************************************************/
     
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    const int N = 1e5+5;
    const int INF=0x3f3f3f3f;
    typedef unsigned long long ULL;
    typedef long long LL;
    int a[N],c[N],pos[N],n,q,cnt;
     
    int root[N],sz;
    struct Node{
      int l,r,v;
    }o[N*25];
     
    void update(int &rt,int l,int r,int x){
       o[++sz]=o[rt],rt=sz;
       ++o[rt].v;
       if(l==r)return;
       int m=(l+r)>>1;
       if(x<=m)update(o[rt].l,l,m,x);
       else update(o[rt].r,m+1,r,x);
    }
     
    int d[N],fa[N][20],head[N],tot;
    struct Edge{
      int v,next;
    }edge[N<<1];
    void add(int u,int v){
      edge[tot].v=v;
      edge[tot].next=head[u];
      head[u]=tot++; 
    }
    void dfs(int u,int f){
       fa[u][0]=f;
       d[u]=d[f]+1;
       update(root[u]=root[f],1,cnt,pos[u]);
       for(int i=head[u];~i;i=edge[i].next){
          int v=edge[i].v;
          if(v==f)continue;
          dfs(v,u);
       }
    }
    int lca(int u,int v){
      if(d[u]<d[v])swap(u,v);
      for(int t=d[u]-d[v],i=0;t;t>>=1,++i)
       if(t&1)u=fa[u][i];
      if(u==v)return u;
      for(int i=19;i>=0;--i){
        if(fa[u][i]!=-1&&fa[u][i]!=fa[v][i])
          u=fa[u][i],v=fa[v][i]; 
      }
      return fa[u][0];
    }
    int query(int u,int v,int k){
      int k1=lca(u,v),k2=fa[k1][0];
      u=root[u],v=root[v],k1=root[k1],k2=root[k2];
      int l=1,r=cnt;
      while(l!=r){
        int m=(l+r)>>1;
        int tmp=o[o[u].l].v+o[o[v].l].v-o[o[k1].l].v-o[o[k2].l].v;
        if(k<=tmp)r=m,u=o[u].l,v=o[v].l,k1=o[k1].l,k2=o[k2].l;
        else l=m+1,k-=tmp,u=o[u].r,v=o[v].r,k1=o[k1].r,k2=o[k2].r;
      }
      return a[l];
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;++i)
          scanf("%d",&a[i]),c[i]=a[i];
        sort(a+1,a+n+1);
        cnt=unique(a+1,a+1+n)-a-1;
        for(int i=1;i<=n;++i)
         pos[i]=lower_bound(a+1,a+1+cnt,c[i])-a;
        tot=root[0]=sz=0;
        memset(head,-1,sizeof(head));
        memset(fa,-1,sizeof(fa));
        for(int i=1;i<n;++i){
          int u,v;
          scanf("%d%d",&u,&v);
          add(u,v),add(v,u);
        }
        dfs(1,0);
        for(int j=1;(1<<j)<=n;++j)
         for(int i=1;i<=n;++i)
          if(fa[i][j-1]!=-1&&i!=1&&j!=0)
           fa[i][j]=fa[fa[i][j-1]][j-1];
        int lastans=0;
        while(q--){
          int u,v,k;
          scanf("%d%d%d",&u,&v,&k);
          u^=lastans;
          printf("%d",lastans=query(u,v,k));
          if(q)printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    基于shell脚本比较数字加减乘除 要bc计算器
    基于shell脚本比较数字大小
    备份WordPress
    在CentOS 7 安装没有mysql
    SQL中判断字符串中包含字符的方法
    ASP.NET生成的HTML代码
    win7禁用休眠,献给c盘空间不足的朋友.
    SQLServer2005和2008的分页技术比较[转]
    浏览器兼容性系列--浅谈window.attachEvent
    在ASP.NET 的服务器端控件中有三种关于 ID 的属性
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5359647.html
Copyright © 2020-2023  润新知