zoukankan      html  css  js  c++  java
  • [bzoj2588]Count on a tree

    传送门

    乍看像是树剖,但是树剖的话就不能用权值线段树,不能权值线段树求区间第k小就只能树套树,诶静态的当然主席树啦!!
    树剖也不需要了诶,好像只需要dfs建主席树就好了,这样建出来的主席树(rt[i]),所包含的就是根到(i)节点路径上的点,对于查询((x,y))就可以差分解决了;
    也就是查询((root,x)+(root,y)-(root,lca(x,y))-(root,f[lca(x,y)]))
    差分部分具体可以看代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<map>
    using namespace std;
    void read(int &x) {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    map<int,int>mp;
    const int maxn=1e5+1;
    int cnt,n,m,lastans,id,rt[maxn],d[maxn],tot,ff[maxn],ls[maxn*20],rs[maxn*20],size[maxn*20],h[maxn],nxt[maxn*2],pre[maxn*2],dep[maxn],f[maxn][20],w[maxn];
    #define rg register
    void update(int x){size[x]=size[ls[x]]+size[rs[x]];}
    void change(int x,int &k,int l,int r,int a)
    {
        k=++id,ls[k]=ls[x],rs[k]=rs[x],size[k]=size[x];
        if(l==r){size[k]++;return ;}
        int mid=(l+r)>>1;
        if(a<=mid)change(ls[x],ls[k],l,mid,a);
        else change(rs[x],rs[k],mid+1,r,a);
        update(k);
    }
    void add(int x,int y)
    {
        pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt;
        pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt;
    }
    void dfs(int x,int fa)
    {
        for(rg int i=1;i<20;i++)
        {
            if((1<<i)>dep[x])break;
            f[x][i]=f[f[x][i-1]][i-1];
        }
        change(rt[fa],rt[x],1,tot,mp[d[x]]);
        for(rg int i=h[x];i;i=nxt[i])if(pre[i]!=fa)f[pre[i]][0]=x,dep[pre[i]]=dep[x]+1,dfs(pre[i],x);
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y])swap(x,y);
        int poor=dep[y]-dep[x];
        for(rg int i=19;i>=0;i--)if(poor&(1<<i))y=f[y][i];
        for(rg int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        return x==y?x:f[y][0];
    }
    int get(int a,int b,int c,int d,int l,int r,int k)
    {
        if(l==r)return w[l];
        int mid=(l+r)>>1,now=size[ls[a]]+size[ls[b]]-size[ls[c]]-size[ls[d]];
        if(k<=now)return get(ls[a],ls[b],ls[c],ls[d],l,mid,k);
        else return get(rs[a],rs[b],rs[c],rs[d],mid+1,r,k-now);
    }
    int main()
    {
        read(n),read(m);
        for(rg int i=1;i<=n;i++)read(d[i]),ff[i]=d[i];
        sort(ff+1,ff+n+1);
        for(rg int i=1;i<=n;i++)if(!mp[ff[i]])mp[ff[i]]=++tot,w[tot]=ff[i];
        for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),add(x,y);
        dfs(1,0);
        for(rg int i=1,x,y,z,fa;i<=m;i++)
        {
            read(x),read(y),read(z),x^=lastans;fa=lca(x,y);
            printf("%d
    ",lastans=get(rt[x],rt[y],rt[fa],rt[f[fa][0]],1,tot,z));
        }
    }
    
  • 相关阅读:
    VB.NET中lambda的写法
    C#中DllImport用法和路径问题
    SQL*Loader 和 Data Pump
    批处理-函数定义及应用01
    Office 2010 KMS激活原理和案例分享
    Hyper-V架构与VMware ESXi的差异
    Tomcat免安装配置2
    Tomcat免安装配置
    域名解析过程
    内部类访问的局部变量必须加final
  • 原文地址:https://www.cnblogs.com/lcxer/p/10255870.html
Copyright © 2011-2022 走看看