zoukankan      html  css  js  c++  java
  • BZOJ2588

    原题链接

    题意简述

    给出一棵带点权的n(n105)个节点的树,Q(Q105)次询问路径(u,v)上第k小的点权值。

    分析

    记节点到根的点权和为dst,则(u,v)上的点权和为dst[u]+dst[v]dst[lca(u,v)]dst[fa[lca(u,v)]]。相似的,对于每个节点,我们用权值线段树记录该节点到根的路径上的点权,这样就可以得到路径(u,v)上的点权了。考虑到每个节点的线段树相当于在其父节点的线段树上进行单点+1,我们可以用可持久化线段树来解决这道题。

    实现

    与普通的可持久化线段树差别不大,只是在查询的时候要多传几个参数。

    代码

    //Count on a tree
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    inline char gc()
    {
        static char now[1<<16],*S,*T;
        if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
        return *S++;
    }
    inline int read()
    {
        int x=0,f=1; char ch=gc();
        while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=gc();}
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x*f;
    }
    int const N=1e5+10;
    int n,m,v[N];
    int num,map[N];
    struct rec{int v,id;} a0[N];
    bool cmpV(rec x,rec y) {return x.v<y.v;}
    int cnt,h[N];
    struct edge{int v,nxt; edge(int u=0,int v1=0){v=v1,nxt=h[u],h[u]=cnt;}} ed[N<<1];
    #define s sg[s0]
    int sgCnt,rt[N];
    struct seg{int cnt; int L,R;} sg[N*20];
    void update(int s0) {s.cnt=sg[s.L].cnt+sg[s.R].cnt;}
    void ins(int &s0,int fr,int to,int v)
    {
        sg[++sgCnt]=s; s0=sgCnt;
        if(fr==to) {s.cnt++; return;}
        int mid=fr+to>>1;
        if(v<=mid) ins(s.L,fr,mid,v);
        else ins(s.R,mid+1,to,v);
        update(s0);
    }
    int query(int s1,int s2,int s3,int s4,int fr,int to,int k)
    {
        if(fr==to) return fr;
        int cntL=sg[sg[s1].L].cnt+sg[sg[s2].L].cnt-sg[sg[s3].L].cnt-sg[sg[s4].L].cnt;
        int mid=fr+to>>1;
        if(k<=cntL) return query(sg[s1].L,sg[s2].L,sg[s3].L,sg[s4].L,fr,mid,k);
        else return query(sg[s1].R,sg[s2].R,sg[s3].R,sg[s4].R,mid+1,to,k-cntL);
    }
    int fa[N][20],dpt[N];
    void trform(int u)
    {
        ins(rt[u]=rt[fa[u][0]],1,num,v[u]);
        for(int i=1;i<=17;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v;
            if(v!=fa[u][0]) fa[v][0]=u,dpt[v]=dpt[u]+1,trform(v);
        }
    }
    int lca(int u,int v)
    {
        if(dpt[u]<dpt[v]) swap(u,v);
        for(int i=17;i>=0;i--) if(dpt[fa[u][i]]>=dpt[v]) u=fa[u][i];
        for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
        return u==v?u:fa[u][0];
    }
    int main()
    {
        n=read(); m=read();
        for(int i=1;i<=n;i++) a0[i].v=read(),a0[i].id=i;
        sort(a0+1,a0+n+1,cmpV);
        num=0;
        for(int i=1;i<=n;i++)
        {
            if(a0[i-1].v!=a0[i].v) map[++num]=a0[i].v;
            v[a0[i].id]=num;
        }
        cnt=0;
        for(int i=1;i<=n-1;i++)
        {
            int u=read(),v=read();
            ed[++cnt]=edge(u,v); ed[++cnt]=edge(v,u);
        }
        rt[0]=sgCnt=0;
        fa[1][0]=0,dpt[1]=1,trform(1);
        int ans=0;
        for(int owo=1;owo<=m;owo++)
        {
            int u=read()^ans,v=read(),k=read(); int w=lca(u,v);
            printf("%d",ans=map[query(rt[u],rt[v],rt[w],rt[fa[w][0]],1,num,k)]);
            if(owo!=m) printf("
    ");
        }
        return 0;
    }

    注意

    本题强制在线,查询时仅需要将u异或lastans即可。非强制在线的原题来自SPOJ.com - Problem COT
    最后一次查询不要输出 ,否则会PE。

  • 相关阅读:
    129. Sum Root to Leaf Numbers
    113. Path Sum II
    114. Flatten Binary Tree to Linked List
    112. Path Sum
    100. Same Tree
    300. Longest Increasing Subsequence
    72. Edit Distance
    自定义js标签库
    JS 实现Table相同行的单元格自动合并示例代码
    mysql 高版本only_full_group_by 错误
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485765.html
Copyright © 2011-2022 走看看