1. 程式人生 > >【SPOJ10628】Count on a tree

【SPOJ10628】Count on a tree

using space 每次 graph 一個點 基礎 insert include n+1

題目大意:給定一棵 N 個節點的樹,點有點權,要求回答 M 個詢問,每次詢問點 u 到點 v 的簡單路徑(鏈)上權值第 K 小是多少。

題解:學習到了樹上主席樹。
主席樹維護序列時,每次將後一個點的樹建立在前一個點的樹上,由此構成一個前綴和,並利用可以在線段樹上二分的性質來求 K 小值。樹上主席樹維護的是每個節點到根節點路徑上的前綴和,即:每個點的主席樹建立在其父節點的主席樹基礎上。回答答案時,只需在 u,v,lca(u,v),fa[lca(u,v)] 的四棵主席樹上面二分答案即可。

代碼如下

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;

int n,m,val[maxn],d[maxn],len;
int f[maxn][21],dep[maxn];
struct Graph{
    int nxt,to;
}e[maxn<<1];
int tot=1,head[maxn];
inline void add_edge(int from,int to){
    e[++tot]=(Graph){head[from],to},head[from]=tot;
}

struct node{
    #define ls(x) t[x].lc
    #define rs(x) t[x].rc
    int lc,rc,sum;
}t[maxn*20];
int cnt,root[maxn];
inline void pushup(int o){t[o].sum=t[ls(o)].sum+t[rs(o)].sum;}
int insert(int pre,int l,int r,int pos,int value){
    int o=++cnt;
    t[o]=t[pre];
    if(l==r){t[o].sum+=value;return o;}
    int mid=l+r>>1;
    if(pos<=mid)ls(o)=insert(ls(pre),l,mid,pos,value);
    else rs(o)=insert(rs(pre),mid+1,r,pos,value);
    return pushup(o),o;
}
int query(int a,int b,int c,int d,int l,int r,int k){
    if(l==r)return l;
    int mid=l+r>>1;
    int sum=t[ls(c)].sum+t[ls(d)].sum-t[ls(a)].sum-t[ls(b)].sum;
    if(k<=sum)return query(ls(a),ls(b),ls(c),ls(d),l,mid,k);
    else return query(rs(a),rs(b),rs(c),rs(d),mid+1,r,k-sum);
}
inline int ask(int x){return lower_bound(d+1,d+len+1,x)-d;}

void read_and_parse(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&val[i]),d[++len]=val[i];
    for(int i=1,x,y;i<n;i++){
        scanf("%d%d",&x,&y);
        add_edge(x,y),add_edge(y,x);
    }
    sort(d+1,d+len+1);
    len=unique(d+1,d+len+1)-d-1;
}

void dfs(int u,int fa){
    dep[u]=dep[fa]+1,f[u][0]=fa;
    for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
    root[u]=insert(root[fa],1,len,ask(val[u]),1);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;if(v==fa)continue;
        dfs(v,u);
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=18;~i;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
    if(x==y)return x;
    for(int i=18;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}

void solve(){
    int lastans=0;
    dfs(1,0);
    while(m--){
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        x=lastans^x;
        int z=lca(x,y);
        printf("%d\n",lastans=d[query(root[f[z][0]],root[z],root[x],root[y],1,len,k)]);
    }
}

int main(){
    read_and_parse();
    solve();
    return 0;
}

【SPOJ10628】Count on a tree