北方多校 又是一道简单题

又是一道简单题

    •  12000ms
    •  65536K

给出一棵有根树,每次查询给出两个节点 u 和 v,假设节点 f 是u,v的最近公共祖先,请查询以 f 为根的子树中,不在 u 到 v 这条链上且标号最小的节点。

输入格式

第一行输入正整数 T(T <= 30),表示共有T组输入数据。

对于每组数据,第一行输入两个正整数 n,m(n <= 50000,m <= 50000),表示节点数和询问数,节点编号 1 到 n,其中 1 是根节点。

接下来 n - 1 行,每行输入两个正整数u,v,表示标号为u和v的节点间有一条边。

接下来 m 行,每行输入两个正整数u,v,表示一次询问。

保证所有输入数据均合法。

输出格式

对于每次询问,输出答案。如不存在输出-1。

样例输入

1
3 3
1 2
1 3
1 2
1 3
2 3

样例输出

3
2
-1
分析:考虑树链剖分;
   把子树按dfs序可以展开到一维,然后对于链,可以将这个区间分成logn的部分,对于每个部分求最小值即可;
   复杂度nlognlogn;
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=n;i++)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define ls rt<<1
#define rs rt<<1|1
#define sys system("pause")
const int maxn=1e5+10;
const int N=1e5+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%mod;p=p*p%mod;q>>=1;}return f;}
int n,m,k,t,st[maxn],ed[maxn],dep[maxn],fa[20][maxn],bel[maxn],son[maxn],pos[maxn],a[maxn],dfs_cl,mi[maxn<<2];
vi e[maxn];
void dfs1(int x,int y)
{
    dep[x]=dep[y]+1;
    fa[0][x]=y;
    son[x]=1;
    for(int i=1;fa[i-1][fa[i-1][x]];i++)
    {
        fa[i][x]=fa[i-1][fa[i-1][x]];
    }
    for(int i=0;i<e[x].size();i++)
    {
        int z=e[x][i];
        if(z==y)continue;
        dfs1(z,x);
        son[x]+=son[z];
    }
}
void dfs2(int x,int y,int ch)
{
    int ma=0;
    pos[x]=++dfs_cl;
    st[x]=dfs_cl;
    a[dfs_cl]=x;
    bel[x]=ch;
    for(int i=0;i<e[x].size();i++)
    {
        int z=e[x][i];
        if(z==y)continue;
        if(son[z]>son[ma])ma=z;
    }
    if(ma!=0)dfs2(ma,x,ch);
    for(int i=0;i<e[x].size();i++)
    {
        int z=e[x][i];
        if(z==y||z==ma)continue;
        dfs2(z,x,z);
    }
    ed[x]=dfs_cl;
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=19;i>=0;i--)if(dep[fa[i][x]]>=dep[y])x=fa[i][x];
    if(x==y)return x;
    for(int i=19;i>=0;i--)
    {
        if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
    }
    return fa[0][x];
}
void pup(int l,int r,int rt)
{
    mi[rt]=min(mi[ls],mi[rs]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        mi[rt]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    pup(l,r,rt);
}
int gao(int L,int R,int l,int r,int rt)
{
    if(L==l&&R==r)return mi[rt];
    int mid=l+r>>1;
    if(R<=mid)return gao(L,R,l,mid,ls);
    else if(L>mid)return gao(L,R,mid+1,r,rs);
    else return min(gao(L,mid,l,mid,ls),gao(mid+1,R,mid+1,r,rs));
}
void upd(vector<int>&a,int x,int y)
{
    while(bel[x]!=bel[y])
    {
        if(dep[bel[x]]<dep[bel[y]])swap(x,y);
        a.pb(pos[x]);
        a.pb(pos[bel[x]]);
        x=fa[0][bel[x]];
    }
    if(pos[x]>pos[y])swap(x,y);
    a.pb(pos[y]);
    a.pb(pos[x]);
}
int main()
{
    int i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        rep(i,1,n)e[i].clear();
        rep(i,1,n)rep(j,0,19)fa[j][i]=0;
        rep(i,1,n-1)scanf("%d%d",&j,&k),e[j].pb(k),e[k].pb(j);
        dfs1(1,0);
        dfs_cl=0;
        dfs2(1,0,1);
        build(1,n,1);
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            vector<int>tmp;
            int lc=lca(x,y);
            upd(tmp,x,y);
            int s=st[lc],t=ed[lc];
            if(lc<1||lc>n)return 0;
            sort(tmp.begin(),tmp.end());
            int mi=1e9;
            for(i=0;i<tmp.size();i+=2)
            {
                if(s<=tmp[i]-1)mi=min(mi,gao(s,tmp[i]-1,1,n,1));
                s=tmp[i+1]+1;
            }
            if(s<=t)mi=min(mi,gao(s,t,1,n,1));
            printf("%d\n",mi==1e9?-1:mi);
        }
    }
    return 0;
}
posted @ 2017-06-09 20:28  mxzf0213  阅读(218)  评论(0编辑  收藏  举报