zoukankan      html  css  js  c++  java
  • [bzoj2588][count on a tree] (主席树+lca)

    Description

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

    Input

    第一行两个整数N,M。
    第二行有N个整数,其中第i个整数表示点i的权值。
    后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
    最后M行每行两个整数(u,v,k),表示一组询问。

    Output

    M行,表示每个询问的答案。

    Sample Input

    8 5
    105 2 9 3 8 5 7 7
    1 2
    1 3
    1 4
    3 5
    3 6
    3 7
    4 8
    2 5 1
    0 5 2
    10 5 3
    11 5 4
    110 8 2

    Sample Output

    2
    8
    9
    105
    7 

    HINT

    N,M<=100000

    暴力自重。。。

    Source

    鸣谢seter

    Solution

    普通的树上主席树

     先上我的TLE树链剖分+主席树

    #include<map>
    #include<vector>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 100010
    #define buf 1<<21
    using namespace std;
    char B[buf],*p=B;
    inline int Rin(){
        int x=0,f=1;
        for(;*p<'0'||*p>'9';p++)
            if(*p=='-')f=-1;
        for(;*p>='0'&&*p<='9';p++)
            x=(x<<1)+(x<<3)+*p-'0';
        return x*f;
    }
    bool vis[N];
    vector<int>d;
    map<int,int>h;
    int ind,n,q,ans,val[N],sz[N],rk[N],id[N],mx[N],fa[N],dep[N],top[N];
    struct pt{
        int v;pt *nt;
    }*fst[N],mem[N<<1],*e=mem;
    inline void link(int x,int y){
        *++e=(pt){y,fst[x]},fst[x]=e;
        *++e=(pt){x,fst[y]},fst[y]=e;
    }
    void dfs1(int x){
        rk[++ind]=x,
        id[x]=ind,
        vis[x]=sz[x]=1;
        for(pt *j=fst[x];j;j=j->nt)
            if(!vis[j->v])
                fa[j->v]=x,
                dep[j->v]=dep[x]+1,
                dfs1(j->v),sz[x]+=sz[j->v],
                mx[x]=sz[mx[x]]<sz[j->v]?j->v:mx[x];
    }
    void dfs2(int x){
        vis[x]=0;
        top[x]=x^mx[fa[x]]?x:top[fa[x]];
        if(mx[x]){
            dfs2(mx[x]);
            for(pt *j=fst[x];j;j=j->nt)
                if(vis[j->v])dfs2(j->v);
        }
    }
    inline int lca(int x,int y){
        while(top[x]^top[y])
            dep[top[x]]>dep[top[y]]?
            x=fa[top[x]]:
            y=fa[top[y]];
        return dep[x]<dep[y]?x:y;
    }
    struct Seg{
        Seg *l,*r;int s;
        Seg(){}
        Seg(Seg *_l,Seg *_r,int _s)
        :l(_l),r(_r),s(_s){}
    }*rt[N],*nil=new Seg(0x0,0x0,0);
    Seg *build(Seg *p,int s,int t,int k){
        if(!(s^t))return new Seg(rt[0],rt[0],p->s+1);
        int mid=s+t>>1;
        return k<=mid?
               new Seg(build(p->l,s,mid,k),p->r,p->s+1):
               new Seg(p->l,build(p->r,mid+1,t,k),p->s+1);
    }
    int secret(Seg *p1,Seg *p2,Seg *p3,Seg *p4,int s,int t,int k){
        while(s<t){
            int mid=s+t>>1;
            int c=p1->l->s+p2->l->s-p3->l->s-p4->l->s;
            if(k<=c)
                t=mid,
                p1=p1->l,
                p2=p2->l,
                p3=p3->l,
                p4=p4->l;
            else
                k-=c,
                s=mid+1,
                p1=p1->r,
                p2=p2->r,
                p3=p3->r,
                p4=p4->r;
        }
        return d[s-1];
    }
    inline int feel(int x,int y,int k){
        int t=lca(x,y);
        return secret(rt[id[x]],rt[id[y]],rt[id[t]],rt[id[fa[t]]],1,d.size(),k);
    }
    int main(){
        fread(B,1,buf,stdin);
        n=Rin(),q=Rin();
        for(int i=1;i<=n;i++)
            val[i]=Rin(),d.push_back(val[i]);
        sort(d.begin(),d.end());
        d.erase(unique(d.begin(),d.end()),d.end());
        for(int i=0;i<d.size();i++)
            h[d[i]]=i+1;
        for(int i=1;i<=n;i++)
            val[i]=h[val[i]];
        for(int i=1;i<n;i++){
            int x=Rin(),y=Rin();
            link(x,y);
        }
        dfs1(1);dfs2(1);
        rt[0]=nil;
        rt[0]->l=rt[0]->r=rt[0];
        for(int i=1;i<=n;i++)
            rt[i]=build(rt[id[fa[rk[i]]]],1,d.size(),val[rk[i]]);
        while(q--){
            int x=Rin(),y=Rin(),k=Rin();
            printf("%d
    ",ans=feel(x^ans,y,k));
        }
        return 0;
    }

    ac倍增+主席树

     注意root的深度不能设为0

    #include<map>
    #include<vector>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=100100;
    inline int Rin(){
        int x=0,c=getchar(),f=1;
        for(;c<48||c>57;c=getchar())
            if(!(c^45))
                f=-1;
        for(;c>47&&c<58;c=getchar())
            x=(x<<1)+(x<<3)+c-48;
        return x*f;
    }
    bool vis[N];
    pair<int,int>v[N];
    int n,m,ecnt,ans,fst[N],q[N],a[N*32],dep[N],fa[N][22],bin[22],rt[N],tot,sum[N*32],ls[N*32],rs[N*32];
    void build(int &pr,int pl,int s,int t,int k){
        pr=++tot;
        sum[pr]=sum[pl]+1;
        if(!(s^t))return;
        ls[pr]=ls[pl];
        rs[pr]=rs[pl];
        int mid=s+t>>1;
        if(k<=mid)build(ls[pr],ls[pl],s,mid,k);
        else build(rs[pr],rs[pl],mid+1,t,k);
    }
    struct edge{
        int v,nxt;
    }e[N<<1];
    inline void link(int x,int y){
        e[++ecnt].v=y;
        e[ecnt].nxt=fst[x];
        fst[x]=ecnt;
    }
    void bfs(){
        int hd=0,tl=1;
        vis[1]=1;q[0]=1;
        while(hd^tl){
            int now=q[hd++];
            build(rt[now],rt[fa[now][0]],1,n,a[now]);
            for(int j=1;j<=19;j++)
                if(bin[j]<=dep[now])
                    fa[now][j]=fa[fa[now][j-1]][j-1];
                else
                    break;
            for(int j=fst[now];j;j=e[j].nxt)
                if(!vis[e[j].v])
                    vis[e[j].v]=1,
                    fa[e[j].v][0]=now,
                    dep[e[j].v]=dep[now]+1,
                    q[tl++]=e[j].v;
        }
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        for(int j=19;~j;j--)
            if(dep[fa[x][j]]>=dep[y])
                x=fa[x][j];
        if(!(x^y))return x;
        for(int j=19;~j;j--)
            if(fa[x][j]^fa[y][j])
                x=fa[x][j],y=fa[y][j];
        return fa[x][0];
    }
    int query(int p1,int p2,int p3,int p4,int s,int t,int k){
        if(!(s^t))return v[t].first;
        int mid=s+t>>1,c=sum[ls[p1]]+sum[ls[p2]]-sum[ls[p3]]-sum[ls[p4]];
        if(k<=c)return query(ls[p1],ls[p2],ls[p3],ls[p4],s,mid,k);
        return query(rs[p1],rs[p2],rs[p3],rs[p4],mid+1,t,k-c);
    }
    int req(int x,int y,int k){
        int t=lca(x,y);
        return query(rt[x],rt[y],rt[t],rt[fa[t][0]],1,n,k);
    }
    int main(){
        for(int i=0;i<=19;i++)
            bin[i]=1<<i;
        n=Rin(),m=Rin();
        for(int i=1;i<=n;i++)
            v[i].first=Rin(),v[i].second=i;
        sort(v+1,v+1+n);
        for(int i=1;i<=n;i++)
            a[v[i].second]=i;
        for(int i=1;i<n;i++){
            int x=Rin(),y=Rin();
            link(x,y);link(y,x);
        }
        dep[1]=1;bfs();
        for(int i=1;i<=m;i++)  
        {
            int x,y,k;
            scanf("%d%d%d",&x,&y,&k);
            printf("%d",ans=req(x^ans,y,k));
            if(i!=m)puts("");
        }
        return 0;
    }

     可持久化线段树注意事项

    1.对于较大的数据范围,用动态开点线段树时注意直接l+r>>1会爆,可以用l+r>>1=(l>>1)+(r>>1)+(l&r&1)

    2.对于lca问题,根节点的深度统一设为1

    3.树剖是O(2n)的,可能会超时,用倍增+宽搜可能稍稍快一些

    4.我认为指针这种东西最好少用,处理不好可能RE

  • 相关阅读:
    Python电影投票系统
    Python打印一个等边三角形
    打印正直角三角形
    MySQL指令
    MySQL安装 8.0.15版本
    局部变量 全局变量
    目录
    格式化输出
    转义字符
    ffmpeg 从内存中读取数据(或将数据输出到内存)
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6247940.html
Copyright © 2011-2022 走看看