Count on a tree

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

N,M<=100000

题解

一开始看了标签:嗯,主席树。那么一定就要放在序列上搞,dfs序。然后又是一条链,树链剖分,每次提取log个区间出来,就像树状数组套主席树一样。

然后就re了。

嗯,上界开小了,离散化。

T了。 (破案了,储存查询的主席树的根的数组没清空)

题解:树上差分,维护点到根的主席树,维护四个根即可x,y,lca,fa[lca]。

然后就A了。

#include<map>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define re register
const int maxn=100005;
int n,m,a[maxn];
int cnt,head[maxn];
int fa[maxn][21],dep[maxn];
int root[maxn],ls[maxn*50],rs[maxn*50],sum[maxn*50];
struct edge{
    int x,y,next;
}e[maxn<<1];

template<class T>inline void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x = f ? -x : x ;
}

void write(int x){
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

void add(int x,int y){
    e[++cnt]=(edge){x,y,head[x]};
    head[x]=cnt;
}

void copy(int x,int y){ls[x]=ls[y];rs[x]=rs[y];sum[x]=sum[y];}

int build(int rt,int l,int r,int pos){
    int t=++cnt;
    copy(t,rt);
    sum[t]++;
    if(l==r) return t;
    int mid=(l+r)>>1;
    if(pos<=mid) ls[t]=build(ls[t],l,mid,pos);
    else rs[t]=build(rs[t],mid+1,r,pos);
    return t;
}

void dfs(int x){
    root[x]=build(root[fa[x][0]],1,n,a[x]);
    for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(y==fa[x][0]) continue;
        fa[y][0]=x;
        dep[y]=dep[x]+1;
        dfs(y);
    }
}

int lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    int delt=dep[y]-dep[x];
    for(int i=0;delt;i++,delt>>=1)
     if(delt&1) y=fa[y][i];
    if(x==y) return x;
    for(int i=20;fa[x][0]!=fa[y][0];i--)
     if(fa[x][i]!=fa[y][i])
      x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int query(int x1,int x2,int y1,int y2,int k){
    int l=1,r=n;
    while(1){
        if(l==r) return l;
        int ret=sum[ls[x1]]+sum[ls[x2]]-sum[ls[y1]]-sum[ls[y2]],mid=(l+r)>>1;
        if(ret>=k){
            x1=ls[x1];x2=ls[x2];y1=ls[y1];y2=ls[y2];
            r=mid;
        }
        else {
            x1=rs[x1];x2=rs[x2];y1=rs[y1];y2=rs[y2];
            l=mid+1;k-=ret;
        }
    }
}

inline int query(int x,int y,int k){
    int t=lca(x,y);
    return query(root[x],root[y],root[t],root[fa[t][0]],k);
}

int tot,b[maxn],cx[maxn];

int main(){
    read(n);read(m);
    for(re int i=1;i<=n;i++) read(a[i]),b[++tot]=a[i];
    sort(b+1,b+n+1);
    tot=unique(b+1,b+tot+1)-b-1;
    for(re int i=1;i<=n;++i){
        int x=lower_bound(b+1,b+tot+1,a[i])-b;
        cx[x]=a[i];
        a[i]=x;
    }
    for(re int i=1;i<n;++i){
        int x,y;
        read(x);read(y);
        add(x,y);add(y,x);
    }
    cnt=0;
    dfs(1);
    int ans=0;
    while(m--){
        int x,y,k;
        read(x);read(y);read(k);
        x^=ans;
        write(ans=cx[query(x,y,k)]);
        putchar(10);
    }
}
树上差分

 

#include<map>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define re register
const int maxn=100005;
int n,m,a[maxn];
int cnt,head[maxn];
int fa[maxn],son[maxn],dep[maxn],size[maxn];
int aa[maxn],id[maxn],top[maxn];
int root[maxn],ls[maxn*50],rs[maxn*50],sum[maxn*50];
struct edge{
    int x,y,next;
}e[maxn<<1];

template<class T>inline void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x = f ? -x : x ;
}

void write(int x){
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

void add(int x,int y){
    e[++cnt]=(edge){x,y,head[x]};
    head[x]=cnt;
}

void dfs(int x){
    size[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(y==fa[x]) continue;
        fa[y]=x;
        dep[y]=dep[x]+1;
        dfs(y);
        if(size[son[x]]<size[y]) son[x]=y;
        size[x]+=size[y];
    }
}

void dfs(int x,int tp){
    id[x]=++cnt;
    aa[cnt]=a[x];
    top[x]=tp;
    if(!son[x]) return ;
    dfs(son[x],tp);
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(y==fa[x]||y==son[x]) continue;
        dfs(y,y);
    }
}

void copy(int x,int y){ls[x]=ls[y];rs[x]=rs[y];sum[x]=sum[y];}

int build(int rt,int l,int r,int pos){
    int t=++cnt;
    copy(t,rt);
    sum[t]++;
    if(l==r) return t;
    int mid=(l+r)>>1;
    if(pos<=mid) ls[t]=build(ls[t],l,mid,pos);
    else rs[t]=build(rs[t],mid+1,r,pos);
    return t;
}

int tp1,tp2,s1[maxn],s2[maxn];

inline int query(int k){
    int l=0,r=n;
    while(1){
        if(l==r) return l;
        int ret=0,mid=(l+r)>>1;
        for(re int i=1;i<=tp1;++i) ret+=sum[ls[s2[i]]]-sum[ls[s1[i]]];
        if(ret>=k){
            for(re int i=1;i<=tp1;++i) s1[i]=ls[s1[i]],s2[i]=ls[s2[i]];
            r=mid;
        }
        else {
            for(re int i=1;i<=tp1;++i) s1[i]=rs[s1[i]],s2[i]=rs[s2[i]];
            l=mid+1;k-=ret;
        }
    }
}

inline int query(int x,int y,int k){
    tp1=tp2=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        s1[++tp1]=root[id[top[y]]-1];
        s2[++tp2]=root[id[y]];
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    s1[++tp1]=root[id[x]-1];
    s2[++tp2]=root[id[y]];
    return query(k);
}

int tot,b[maxn],cx[maxn];

int main(){
    read(n);read(m);
    for(re int i=1;i<=n;i++) read(a[i]),b[++tot]=a[i];
    sort(b+1,b+n+1);
    tot=unique(b+1,b+tot+1)-b-1;
    for(re int i=1;i<=n;++i){
        int x=lower_bound(b+1,b+tot+1,a[i])-b;
        cx[x]=a[i];
        a[i]=x;
    }
    for(re int i=1;i<n;++i){
        int x,y;
        read(x);read(y);
        add(x,y);add(y,x);
    }
    cnt=0;
    dfs(1);
    dfs(1,1);
    for(re int i=1;i<=n;++i) root[i]=build(root[i-1],0,n,aa[i]);
    int ans=0;
    while(m--){
        int x,y,k;
        read(x);read(y);read(k);
        x^=ans;
        write(ans=cx[query(x,y,k)]);
        putchar(10);
    }
}
树链剖分

 

然后关于静态k大

posted @ 2019-10-09 21:27  _JSQ  阅读(168)  评论(0编辑  收藏  举报