ONTAK

来源:互联网 发布:js防水涂料与水泥结合 编辑:程序博客网 时间:2024/06/05 19:58

ONTAK - 2010 - aut
给一棵 n 个点的树以及 m 条额外的双向边
q 次询问,统计满足以下条件的 uv 的路径数量:
恰经过一条额外的边
不经过树上 uv 的路径上的边

对于一个询问 (u,v) ,答案就是两个端点分别在 u 的子树和 v 的子树中的边。因为是子树,所以在dfs序上。考虑用线段树维护边在每个点的子树中的另一个端点的位置。然后可以进行线段树合并。

dfs离线处理询问就行了。

#include<bits/stdc++.h>using namespace std;const int N=1e5+7;vector<int> adj[N],ext[N];struct Query{    int v,id;};vector<Query> q[N];int n,Ans[N*5],sz[N],d[N],id[N],gg;namespace LCA{    int ord[N<<1],d[N<<1],fir[N],dp[N<<1][20],mm[N<<1],m=0;    void dfs_lca(int u,int p,int deep)    {        ord[++m]=u;        d[m]=deep;        fir[u]=m;        for(int i=0;i<adj[u].size();++i)        {            int v=adj[u][i];            if(v==p) continue;            dfs_lca(v,u,deep+1);            ord[++m]=u;            d[m]=deep;        }    }    void init_RMQ()    {        mm[0] = -1;        for(int i=1;i<=m;++i)        {            mm[i]= ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];            dp[i][0]=i;        }        for(int j=1;j<=mm[m];++j)            for(int i=1;i+(1<<j)-1<=m;++i)            {                int x=dp[i][j-1],y=dp[i+(1<<(j-1))][j-1];                dp[i][j]=d[x]<d[y]?x:y;            }    }    int lca(int u,int v)    {        u=fir[u],v=fir[v];        if(u>v) swap(u,v);        int k=mm[v-u+1];        int x=dp[u][k],y=dp[v-(1<<k)+1][k];        return d[x]<d[y]?ord[x]:ord[y];    }    void init(int u)    {        m=0;        dfs_lca(u,0,0);        init_RMQ();    }}namespace SegmentTree{    int sum[N*9],s[N*9],top=0,tot=0,ls[N*9],rs[N*9];    int newnode()    {        int id;        if(top) id=s[--top];        else id=++tot;        sum[id]=ls[id]=rs[id]=0;        return id;    }    void delnode(int x)    {        s[top++]=x;    }    void build(int &rt,int l,int r,int p)    {        rt=newnode();        sum[rt]=1;        if(l==r) return ;        int mid=(l+r)>>1;        if(p<=mid) build(ls[rt],l,mid,p);        else build(rs[rt],mid+1,r,p);    }    int Merge(int rt1,int rt2)    {        if(rt1==0||rt2==0) return rt1^rt2;        ls[rt1]=Merge(ls[rt1],ls[rt2]);        rs[rt1]=Merge(rs[rt1],rs[rt2]);        sum[rt1]=sum[rt1]+sum[rt2];        delnode(rt2);        return rt1;    }    int query(int rt,int l,int r,int ql,int qr)    {        if(!rt) return 0;        if(ql<=l&&qr>=r) return sum[rt];        int mid=(l+r)>>1;        int res=0;        if(ql<=mid) res+=query(ls[rt],l,mid,ql,qr);        if(qr>mid) res+=query(rs[rt],mid+1,r,ql,qr);        return res;    }    int dfs(int u,int p)    {        int rt=newnode();        for(int i=0;i<adj[u].size();++i)        {            int v=adj[u][i];            if(v==p) continue;            Merge(rt,dfs(v,u));        }        for(int i=0;i<ext[u].size();++i)        {            int root=newnode();            build(root,1,n,id[ext[u][i]]);            Merge(rt,root);        }        for(int i=0;i<q[u].size();++i)        {            int v=q[u][i].v;            if(LCA::lca(u,v)==v)            {                int son;                for(int i=0;i<adj[v].size();++i)                    if(LCA::lca(son=adj[v][i],u)==son&&d[son]>d[v]) break;                Ans[q[u][i].id]=query(rt,1,n,1,n)-query(rt,1,n,id[son],id[son]+sz[son]-1);            }            else  Ans[q[u][i].id]=query(rt,1,n,id[v],id[v]+sz[v]-1);        }        return rt;    }}void dfs(int u,int p,int deep){    d[u]=deep;    sz[u]=1;    id[u]=++gg;    for(int i=0;i<adj[u].size();++i)    {        int v=adj[u][i];        if(v==p) continue;        dfs(v,u,deep+1);        sz[u]+=sz[v];    }}int main(){    scanf("%d",&n);    for(int i=1; i<n; ++i)    {        int u,v;        scanf("%d%d",&u,&v);        adj[u].push_back(v);        adj[v].push_back(u);    }    dfs(1,0,0);    LCA::init(1);    int m;    scanf("%d",&m);    for(int i=0;i<m;++i)    {        int u,v;        scanf("%d%d",&u,&v);        ext[u].push_back(v);        ext[v].push_back(u);    }    scanf("%d",&m);    for(int i=0;i<m;++i)    {        int u,v;        scanf("%d%d",&u,&v);        if(d[u]>d[v]) q[u].push_back({v,i});        else q[v].push_back({u,i});    }    SegmentTree::dfs(1,0);    for(int i=0;i<m;++i)        printf("%d\n",Ans[i]+1);    return 0;}
原创粉丝点击