• BZOJ2588 Count on a tree


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2588

    知识点:  可持久化线段树

    解题思路:

      先建一棵空的权值线段树,然后按照题目给出的树以任意一点为根的(DFS)序来更新这棵线段树。询问((u,v,k))时,其实就是查询(T[u])所对应的线段树加上(T[v])所对应的线段树减去(T[u and v's LCA])所对应的线段树再减去(T[fa[u and v's LCA]]),(LCA)就是最近公共祖先。(从题解那里学到了一种类似二分的(query)的方法)

    AC代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int maxn = 100000+5;
      4 int inp[maxn];  //原始输入
      5 int num[maxn],san[maxn];    //san[]:离散化; num[]:下标是DFS序(从1开始),表示这个数在san[]中是第几个
      6 int pos[maxn];      //num[]的下标->inp[]的下标
      7 int rpos[maxn];     //inp[]的下标->num[]的下标
      8 int tot=0,xu=1;
      9 int sum[maxn*20];
     10 int T[maxn*20],lson[maxn*20],rson[maxn*20];
     11 vector<int> G[maxn];
     12 int par[20][maxn],depth[maxn];      //LCA
     13 
     14 void build(int l,int r,int &rt){
     15     rt=++tot;
     16     sum[rt]=0;
     17     if(l==r)    return;
     18     int m=(l+r)>>1;
     19     build(l,m,lson[rt]);    build(m+1,r,rson[rt]);
     20 }
     21 void update(int last,int pos,int l,int r,int &rt){
     22     rt=++tot;
     23     sum[rt]=sum[last]+1;
     24     if(l==r)    return;
     25     lson[rt]=lson[last];
     26     rson[rt]=rson[last];
     27     int m=(l+r)>>1;
     28     if(pos<=m)  update(lson[last],pos,l,m,lson[rt]);
     29     else        update(rson[last],pos,m+1,r,rson[rt]);
     30 }
     31 int lca(int u,int v){
     32     if(depth[u]>depth[v])   swap(u,v);
     33     for(int k=0;k<20;k++){
     34         if((depth[v]-depth[u])>>k&1){
     35             v=par[k][v];
     36         }
     37     }
     38     if(u==v)    return u;
     39     for(int k=19;k>=0;k--){
     40         if(par[k][u]!=par[k][v]){
     41             u=par[k][u];
     42             v=par[k][v];
     43         }
     44     }
     45     return par[0][u];
     46 }
     47 void dfs(int v,int p,int d,int cnt){
     48     num[xu]=lower_bound(san + 1, san + cnt + 1, inp[v]) - san;
     49     pos[xu]=v,rpos[v]=xu;
     50     xu++;
     51 
     52     par[0][v]=p;
     53     depth[v]=d;
     54     for(int i=0;i<G[v].size();i++){
     55         if(G[v][i]!=p)  dfs(G[v][i],v,d+1,cnt);
     56     }
     57 }
     58 void init(int N,int cnt){
     59     dfs(1,0,1,cnt);
     60     for(int k=0;k+1<20;k++){
     61         for(int v=1;v<=N;v++){
     62             if(par[k][v]<=0) par[k+1][v]=0;
     63             else    par[k+1][v]=par[k][par[k][v]];
     64         }
     65     }
     66 }
     67 int que(int x,int y,int rk,int cnt){
     68     int a=x,b=y,c=lca(x,y),d=par[0][c];
     69     a=T[rpos[a]],b=T[rpos[b]],c=T[rpos[c]],d=T[rpos[d]];
     70     int l=1,r=cnt;
     71     int ret=1;
     72     while(l<r){
     73         int m=(l+r)>>1;
     74         int tmp=sum[lson[a]]+sum[lson[b]]-sum[lson[c]]-sum[lson[d]];
     75         if(tmp>=rk) r=m,a=lson[a],b=lson[b],c=lson[c],d=lson[d];
     76         else    rk-=tmp,l=m+1,a=rson[a],b=rson[b],c=rson[c],d=rson[d];
     77     }
     78     return san[l];
     79 }
     80 int main(){
     81 //    freopen("in.txt","r",stdin);
     82     int N,M;
     83     int u,v,k;
     84     scanf("%d%d",&N,&M);
     85     for(int i=1;i<=N;i++){
     86         scanf("%d",&inp[i]);
     87         san[i]=inp[i];
     88     }
     89     sort(san+1,san+1+N);
     90     int cnt=unique(san+1,san+1+N)-san-1;
     91     build(1,cnt,T[0]);  //先建一棵空树
     92     for(int i=1;i<N;i++){
     93         scanf("%d%d",&u,&v);
     94         G[u].push_back(v);
     95         G[v].push_back(u);
     96     }
     97     init(N,cnt);
     98     for(int i=1;i<=N;i++){
     99         int now=pos[i];
    100         int fa=par[0][now];
    101         update(T[rpos[fa]],num[i],1,cnt,T[i]);  //旧版本是该点的父亲所对应的那个版本
    102     }
    103     int last=0;
    104     while(M--){
    105         scanf("%d%d%d",&u,&v,&k);
    106         u^=last;
    107         last=que(u,v,k,cnt);
    108         printf("%d",last);
    109         if(M)   printf("
    ");
    110     }
    111 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    【LeetCode】297. 二叉树的序列化与反序列化
    【剑指Offer】面试题37. 序列化二叉树
    【剑指Offer】面试题59
    【剑指Offer】面试题57
    趣图:向客户介绍的产品VS实际开发的产品
    Spring AOP的实现机制
    Mysql高性能优化规范建议
    JavaScript八张思维导图
    深入 Nginx:我们是如何为性能和规模做设计的
    教你用认知和人性来做最棒的程序员
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/8366706.html
Copyright © 2020-2023  润新知