首页 > 其他 > 详细

Count on a tree

时间:2019-10-09 21:37:36      阅读:101      评论:0      收藏:0      [点我收藏+]

给定一棵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);
    }
}
树上差分

不过讲道理,$O(nlog^{2}n)$也至于慢那么多(第一个点就60s,还是加了各种优化)。

然后关于静态k大

Count on a tree

原文:https://www.cnblogs.com/sto324/p/11644488.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!