码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2588: Spoj 10628. Count on a tree

时间:2016-07-11 20:51:51      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

主席树。

求a到b的路径可以看作a到根和b到根的路径的一部分。

对于每个节点,需要查询它到根路径各个数出现的次数。

如果对于每个节点都建一棵权值线段树,肯定会爆掉。

这时用主席树,该节点的权值线段树由父亲的权值线段树转移而来。

建树之前,要对整个数进行重标号,建树的时候才能保证父亲的树已经被建了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxd = 18;
const int maxn = 100000 + 10;
const int maxm = 200000 + 10;
const int maxx = 4000000 + 10;

int n,m,q,la,cnt,size;
int g[maxn],v[maxm],next[maxm],eid;
int anc[maxn][maxd+5];
int h[maxn];
int num[maxn],pos[maxn];
int lc[maxx],rc[maxx],s[maxx];
int a[maxn],t[maxn];
int root[maxn];

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;    
}

void dfs(int u) {
    num[++cnt]=u; pos[u]=cnt;
    for(int d=1;d<maxd;d++) anc[u][d]=anc[anc[u][d-1]][d-1];
    for(int i=g[u];~i;i=next[i]) if(v[i]!=anc[u][0]) {
        anc[v[i]][0]=u;
        h[v[i]]=h[u]+1;
        dfs(v[i]);    
    }
}

int LCA(int a,int b) {
    if(h[a]<h[b]) swap(a,b);
    for(int i=maxd-1;i>=0;i--) if(h[anc[a][i]]>=h[b]) a=anc[a][i];
    if(a==b) return a;
    for(int i=maxd-1;i>=0;i--) 
        if(anc[a][i]!=anc[b][i]) {
            a=anc[a][i];
            b=anc[b][i];
        }
    return anc[a][0];
}

void modify(int &x,int y,int L,int R,int pos) {
    x=++size; s[x]=s[y]+1;
    lc[x]=lc[y],rc[x]=rc[y];
    if(L==R) return;
    
    int mid=(L+R)>>1;
    if(pos<=mid) modify(lc[x],lc[y],L,mid,pos);
    else modify(rc[x],rc[y],mid+1,R,pos);    
}

int query(int a,int b,int k) {
    int c=LCA(a,b),d=anc[c][0];
    
    a=root[pos[a]]; b=root[pos[b]]; c=root[pos[c]]; d=root[pos[d]];
    int l=1,r=m,mid,cur;
    while(l<r) { 
        mid=(l+r)>>1;
        cur=s[lc[a]]+s[lc[b]]-s[lc[c]]-s[lc[d]];
        if(k<=cur) {
            a=lc[a]; b=lc[b]; c=lc[c]; d=lc[d]; r=mid;    
        }
        else {
            a=rc[a]; b=rc[b]; c=rc[c]; d=rc[d]; l=mid+1; k-=cur;
        }
    }
    return t[l];
}

int main() {
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&q);    
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    m=unique(t+1,t+n+1)-(t+1);
    for(int i=1;i<=n;i++) a[i]=lower_bound(t+1,t+m+1,a[i])-t;
    for(int i=1,u,v;i<n;i++) {
        scanf("%d%d",&u,&v);
        addedge(u,v);
    }
    cnt=0; h[1]=1; anc[1][0]=0;
    dfs(1);
        
    root[0]=lc[0]=rc[0]=s[0]=0;
    for(int i=1;i<=n;i++)
        modify(root[i],root[pos[anc[num[i]][0]]],1,m,a[num[i]]);
    la=0;
    
    for(int i=1,u,v,k;i<=q;i++) {
        scanf("%d%d%d",&u,&v,&k);
        u^=la;
        printf("%d",la=query(u,v,k));
        if(i!=q) printf("\n");
    }
    return 0;
}

bzoj2588: Spoj 10628. Count on a tree

标签:

原文地址:http://www.cnblogs.com/invoid/p/5661344.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!