【jzoj5290】【NOIP2017提高组A组模拟8.17】【行程的交集】

Description

豪哥生活在一个n个点的树形城市里面,每一天都要走来走去。虽然走的是比较的多,但是豪哥在这个城市里面的朋友并不是很多。

当某一天,猴哥给他展现了一下大佬风范之后,豪哥决定要获得一些交往机会来提升交往能力。豪哥现在已经物色上了一条友,打算和它(豪哥并不让吃瓜群众知道性别)交往。豪哥现在spy了一下这个人的所有行程起点和终点,豪哥打算从终点开始走到起点与其相遇。但是豪哥是想找话题的,他想知道以前有多少次行程和此次行程是有交集的,这样豪哥就可以搭上话了。这个路径与之前路径的有交集数量作为豪哥此次的交往机会。

但是豪哥急着要做交往准备,所以算什么交往机会的小事情就交给你了。

Solution

这题其实很妙,两条路径有交有两种情况,lca在当前路径上,lca在根到当前lca路径上。第一种情况建一个树状数组,加入路径时lca dfn打+1,leave+1打-1,贡献为1~u+1~v-2*1~lca。第二种情况另建一个树状树状数组,加入路径u,v打+1,lca打-2,贡献为lca dfn~leave。

code

#include
#include
#include
#include
#include
#define LL long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=2*1e5+9,mm=4*1e5+9,mo=1e9+7;
int n,m,gra,lg2,tim,dep[mn],fa[mn][19],begin[mn],to[mm],next[mm],dfn[mn],
    end[mn],tr[mn][2],cnt[mn];
void insert(int u,int v){
    to[++gra]=v;
    next[gra]=begin[u];
    begin[u]=gra;
}
void dfs(int p,int q){
    dfn[p]=++tim;
    fa[p][0]=q;
    dep[p]=dep[q]+1;
    fr(i,p)if(to[i]!=q)dfs(to[i],p);
    end[p]=tim;
}
int lc(int u,int v){
    if(dep[u]0)if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
    if(u==v)return u;
    fd(i,lg2,0)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
void oper(int p,int op,int v){
    while(p<=n){
        tr[p][op]+=v;
        p+=p&(-p);
    }
}
int qury(int p,int op){
    int ans=0;
    while(p>0){
        ans+=tr[p][op];
        p-=p&(-p);
    }
    return ans;
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n-1){
        int u,v;
        scanf("%d%d",&u,&v);
        insert(u,v);
        insert(v,u);
    }
    dfs(1,0);
    lg2=log(n)/log(2);
    fo(j,1,lg2)fo(i,1,n)fa[i][j]=fa[fa[i][j-1]][j-1];
    scanf("%d",&m);
    fo(cas,1,m){
        int u,v;
        scanf("%d%d",&u,&v);
        int lca=lc(u,v);
        printf("%d\n",qury(dfn[u],1)+qury(dfn[v],1)-2*qury(dfn[lca],1)+
            qury(end[lca],2)-qury(dfn[lca]-1,2)+cnt[lca]);
        cnt[lca]++;
        oper(dfn[lca],1,1);
        oper(end[lca]+1,1,-1);
        oper(dfn[lca],2,-2);
        oper(dfn[u],2,1);
        oper(dfn[v],2,1);
    }
    return 0;
}

你可能感兴趣的:(jzoj,数据结构)