BZOJ 2588 & SPOJ 10628:树上主席树

来源:互联网 发布:iptv服务器软件 编辑:程序博客网 时间:2024/05/16 17:13

BZOJ强制在线,所以大多数RE==WA

SPOJ比较坑,大多数WA是因为数组没开够(n实际上大于1e5。。。题目数据的锅)。


题意:给出一棵树,树上每个点有一个权值,现在有若干询问,每次询问(u,v,k)求出u-v路径上权值第k小的是什么。


题解:在树上构造主席树,每个点记录该点到根路径上所有点。然后u-v的路径 需要用 u+v-lca(u,v)-father[lca(u,v)]来得到,画个图或者想象一下是很好理解的。

注意LCA不要写丑了。


代码:

#include<bits/stdc++.h>#define l(x) tree[x].L#define r(x) tree[x].Rusing namespace std;const int maxn = 1e5+1000;struct Node{    int L,R,val;}tree[maxn*40];int root[maxn];vector<int> E[maxn];int a[maxn];int rk[maxn];int pos[maxn];int st[maxn][21];int dep[maxn];int cnt,m,n;int lastans=0;void input(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++){        scanf("%d",a+i);        rk[i]=i;    }    for (int i=1;i<n;i++){        int u,v;        scanf("%d%d",&u,&v);        E[u].push_back(v);        E[v].push_back(u);    }}bool cmp(int x,int y){    return a[x]<a[y];}int build (int l,int r){    int k = cnt++;    tree[k].val =0;    if (l==r)return k;    int mid = l+r >>1;    tree[k].L = build(l,mid);    tree[k].R = build (mid+1,r);    return k;}int update(int P,int l,int r,int pos,int del){    int k = cnt++;    tree[k].val = tree[P].val+del;    if (l==r) return k;    int mid = l+r >>1;    if (pos<=mid){        tree[k].L = update(tree[P].L,l,mid,pos,del);        tree[k].R = tree[P].R;    }else{        tree[k].L = tree[P].L;        tree[k].R = update(tree[P].R,mid+1,r,pos,del);    }    return k;}void dfs(int node,int father){    root[node] = update(root[father],1,n,pos[node],1);    st[node][0] =father;    dep[node] = dep[father]+1;    for (int i=1;i<=19;i++){        st[node][i] = st[st[node][i-1]][i-1];        if (!st[node][i]){            break;        }    }    for (vector<int>::iterator it = E[node].begin();it!=E[node].end();++it){        int v = *it;        if (v==father)continue;        dfs(v,node);    }}void presolve(){    sort(rk+1,rk+1+n,cmp);    for (int i=1;i<=n;i++){        pos[rk[i]] =i;    }    root[0] = build(1,n);    dfs(1,0);}int lca(int u,int v){    if (dep[u]<dep[v]){        swap(u,v);    }    for (int i=19;i>=0;i--){        if (dep[st[u][i]]>=dep[v]){            u = st[u][i];        }    }    if (u==v){        return u;    }    for (int i=19;i>=0;i--){        if (st[u][i]!=st[v][i]){            u = st[u][i];            v = st[v][i];        }    }    return st[u][0];}int query_kth(int rtx,int rty,int anc,int fanc,int l,int r,int k){    if (l==r)return l;    int mid = l+r>>1;    int temp = tree[l(rtx)].val+tree[l(rty)].val-tree[l(anc)].val-tree[l(fanc)].val;    if (temp>=k)return query_kth(tree[rtx].L,tree[rty].L,tree[anc].L,tree[fanc].L,l,mid,k);    else return query_kth(tree[rtx].R,tree[rty].R,tree[anc].R,tree[fanc].R,mid+1,r,k-temp);}int query(int x,int y,int k){    int anc = lca(x,y);//    printf("x=%d y=%d anc =%d ",x,y,anc);    int tmp=query_kth(root[x],root[y],root[anc],root[st[anc][0]],1,n,k);//    cout<<tmp<<endl;    return a[rk[tmp]];}void solve(){    while (m--){        int x,y,k;        scanf("%d%d%d",&x,&y,&k);        x =x^lastans;        lastans = query(x,y,k);        printf("%d",lastans);        if (m){            printf("\n");        }    }}int main(){    input();    presolve();    solve();    return 0;}


阅读全文
0 0
原创粉丝点击