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。

  • 相关阅读:
    获取指定函数的函数名称(用于兼容IE)
    opa gatekeeper笔记:AdmissionReview input.request请求对象结构
    团队内部密码共享方案:KeePassXC+微盘(企业微信)
    一个简单的golang项目,实验 gitlab-ci-cd Pipelines
    调用企业微信API拨打紧急通知电话
    使用PAM模块实现普通用户之间su免密切换
    thin_check命令 man手册
    Nginx server_name翻译
    UDP端口检查告警SHELL脚本(企业微信版机器人版)
    从零搭建vsftpd
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485765.html
Copyright © 2011-2022 走看看