• [bzoj2588][Spoj 10628] Count on a tree


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。   n,m<=100000
     
    题解:
    查的是链,很容易想到树剖。然后我们按照dfs序建一棵主席树,每次询问找到最多log个根同时移动。期望复杂度nlogn(loglogn)
    然后去百度了一下,学习了一个新姿势  树上主席树。每个点存一下它到根的路径上的权值,建树的时候直接可持久化,查询的时候直接用两个点的加起来减去lca处的就行了。复杂度是nlogn  
    讲道理这样会比树剖快,但是可能是数据原因,跑的没有树剖快qaq
    两个的代码都贴一下
     
    树剖+主席树
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define mp(x,y) make_pair(x,y)
    #define MN 100000
    #define ll long long
    using namespace std;
    inline ll read()
    {
    //    int x;scanf("%lld",&x);return x;
        ll x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    ll last=0;
    int n,m,mx[MN+5],size[MN+5],dfn[MN+5],dn=0,cnt=0,dep[MN+5],tot=1;
    int a[MN+5],p[MN+5],head[MN+5],top[MN+5],fa[MN+5],rt[MN+5],tp,L[MN+5];
    pair<int,int> q[MN+5];
    struct node{int l,r,x;}T[MN*30];
    struct edge{int to,next;}e[MN*2+5];
    
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void dfs1(int x,int f)
    {
        mx[x]=0;size[x]=1;fa[x]=f;    
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=f)
            {
                dep[e[i].to]=dep[x]+1;dfs1(e[i].to,x);
                size[x]+=size[e[i].to];
                if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to;
            }
    }
    
    void dfs2(int x,int tp)
    {
        dfn[x]=++dn;p[dn]=x;top[x]=tp;
        if(mx[x]) dfs2(mx[x],tp);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa[x]&&e[i].to!=mx[x])
                dfs2(e[i].to,e[i].to);
    }
    
    void ins(int x,int nx,int k)
    {
        int l=1,r=tot,mid;
        while(l<r)
        {
            mid=l+r>>1;
            if(k<=mid)
            {
                T[nx].r=T[x].r;T[nx].l=++cnt;
                x=T[x].l;nx=T[nx].l;r=mid;
            }
            else
            {
                T[nx].l=T[x].l;T[nx].r=++cnt;
                x=T[x].r;nx=T[nx].r;l=mid+1; 
            }
            T[nx].x=T[x].x+1;
        }
    }
    
    void getrt(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            q[++tp]=mp(rt[dfn[x]],rt[dfn[top[x]]-1]);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        q[++tp]=mp(rt[dfn[y]],rt[dfn[x]-1]);
    }
    
    main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++) L[i]=a[i]=read();
        sort(L+1,L+n+1);
        for(int i=2;i<=n;i++) if(L[i]!=L[i-1]) L[++tot]=L[i];
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            ins(u,v);    
        }
        cnt=0;dfs1(1,0);dfs2(1,1);
        for(int i=1;i<=n;i++) ins(rt[i-1],rt[i]=++cnt,(a[p[i]]=lower_bound(L+1,L+tot+1,a[p[i]])-L));
        for(int i=1;i<=m;i++)
        {
            ll x=read()^last;int y=read(),k=read();tp=0;
            getrt(x,y);
            int l=1,r=tot,mid;
            while(l<r)
            {
                int sum=0;mid=l+r>>1;
                for(int j=1;j<=tp;j++)
                    sum+=T[T[q[j].first].l].x-T[T[q[j].second].l].x;
                if(sum<k) 
                {
                    k-=sum;l=mid+1;
                    for(int j=1;j<=tp;j++)
                        q[j]=mp(T[q[j].first].r,T[q[j].second].r);
                }
                else 
                {
                    r=mid;
                    for(int j=1;j<=tp;j++)
                        q[j]=mp(T[q[j].first].l,T[q[j].second].l);
                }
            }
            printf("%lld",last=L[l]);if(i!=m) puts("");
        }
        return 0;
    }

    树上主席树

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define MN 100000
    #define MK 18
    #define ll long long
    using namespace std;
    inline ll read()
    {
        ll x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    ll last=0;
    int n,m,cnt=0,dep[MN+5],tot=1,a[MN+5],head[MN+5],fa[MN+5][MK+2],rt[MN+5],L[MN+5];
    struct node{int l,r,x;}T[MN*30];
    struct edge{int to,next;}e[MN*2+5];
    
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void dfs1(int x,int f)
    {
        fa[x][0]=f;    
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=f) dep[e[i].to]=dep[x]+1,dfs1(e[i].to,x);
    }
    
    void ins(int x,int nx,int k)
    {
        int l=1,r=tot,mid;
        while(l<r)
        {
            mid=l+r>>1;
            if(k<=mid)
            {
                T[nx].r=T[x].r;T[nx].l=++cnt;
                x=T[x].l;nx=T[nx].l;r=mid;
            }
            else
            {
                T[nx].l=T[x].l;T[nx].r=++cnt;
                x=T[x].r;nx=T[nx].r;l=mid+1; 
            }
            T[nx].x=T[x].x+1;
        }
    }
    
    void init(int x)
    {
        ins(rt[fa[x][0]],rt[x]=++cnt,a[x]=lower_bound(L+1,L+tot+1,a[x])-L);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa[x][0]) init(e[i].to);
    }
    
    int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
            if(k&1) x=fa[x][j];
        if(x==y) return x;
        for(int i=MK;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++) L[i]=a[i]=read();
        sort(L+1,L+n+1);
        for(int i=2;i<=n;i++) if(L[i]!=L[i-1]) L[++tot]=L[i];
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            ins(u,v);    
        }
        dfs1(1,0);cnt=0;init(1);
        for(int i=1;i<=MK;i++)
            for(int j=1;j<=n;j++)
                fa[j][i]=fa[fa[j][i-1]][i-1];
        for(int i=1;i<=m;i++)
        {
            int x=(int)(read()^last),y=read(),k=read(),b;
            int l=1,r=tot,mid;int z=rt[b=lca(x,y)];x=rt[x];y=rt[y];
            while(l<r)
            {
                mid=l+r>>1;int sum=T[T[x].l].x+T[T[y].l].x-2*T[T[z].l].x+(a[b]>=l&&a[b]<=mid);
                if(sum<k) k-=sum,x=T[x].r,y=T[y].r,z=T[z].r,l=mid+1;
                else x=T[x].l,y=T[y].l,z=T[z].l,r=mid;
            }
            printf("%lld",last=L[l]);if(i!=m) puts("");
        }
        return 0;
    }
  • 相关阅读:
    C#中静态与非静态方法比较
    Hibernate学习之路-- -映射 继承关系(subclass , joined-subclass,union-subclass )
    网络协议概述:物理层、连接层、网络层、传输层、应用层详解
    phpstorm xdebug配置
    eclipse修改内存大小
    Session机制详解
    java把html标签字符转普通字符(反转换成html标签)(摘抄)
    JAVA调用WCF
    RabbitMQ入门与使用篇
    大话程序猿眼里的高并发
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2588.html
Copyright © 2020-2023  润新知