HDU4822XSY2021Tri-war

Posted ez-lcw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU4822XSY2021Tri-war相关的知识,希望对你有一定的参考价值。

如果题目中只有两个国家,事情就非常简单了:假设只有国家\(A\)\(B\),我们先找出\(A\)\(B\)的最近公共祖先\(lca\),然后找到在路径\(A\longrightarrow lca\longrightarrow B\)上的中点\(mid\),然后分3类讨论:

  1. \(dis(A,mid)==dis(B,mid)\),则\(A\)在这条路径上能到达的范围是\([A,mid)\)\(B\)在这条路径上能到达的范围是\((mid,B]\)。那么\(A\)在全树所能到达的点数为:

    \[ \begincases size[son] & \textif deep[A]>deep[B] & (son=在路径[mid,A]上的mid的儿子)\ n-size[mid] & \textif deep[B]>deep[A] \endcases\]

    \(B\)在全树能到达的点数为:

    \[ \begincases n-size[mid] & \textif deep[A]>deep[B]\ size[son] & \textif deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \endcases \]

  2. \(dis(A,mid)<dis(B,mid)\),则\(A\)在这条路径上能到达的范围是\([A,mid]\)\(B\)在这条路径上能到达的范围是\((mid,B]\)。那么\(A\)在全树所能到达的点数为:

    \[ \begincases size[mid] & \textif deep[A]>deep[B]\ n-size[son] & \textif deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \endcases\]

    \(B\)在全树能到达的点数为:

    \[ \begincases n-size[mid] & \textif deep[A]>deep[B]\ size[son] & \textif deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \endcases \]

  3. \(dis(A,mid)>dis(B,mid)\),那就把\(A\)\(B\)交换一下就和情况2一样了。

那么对于三个点的情况,只需对于每个点求出与另外两个点所能到的范围,再取并集就好了。

代码如下:

#include<bits/stdc++.h>
 
#define N 100010
#define LN 18
 
using namespace std;
 
struct data

    bool opt;
    int u;
    data();
    data(bool a,int b)opt=a,u=b;
;
 
int t,n,m;
int cnt,head[N],nxt[N<<1],to[N<<1];
int fa[N][LN],d[N],size[N];
 
void init()

    cnt=0;
    memset(head,0,sizeof(head));

 
void adde(int u,int v)

    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;

 
void dfs(int u)

    size[u]=1;
    for(int i=1;i<=17;i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=head[u];i;i=nxt[i])
    
        if(to[i]!=fa[u][0])
        
            d[to[i]]=d[u]+1;
            fa[to[i]][0]=u;
            dfs(to[i]);
            size[u]+=size[to[i]];
        
    

 
int lca(int a,int b)

    if(d[a]<d[b])
        swap(a,b);
    for(int i=17;i>=0;i--)
        if(d[fa[a][i]]>=d[b])
            a=fa[a][i];
    if(a==b)
        return a;
    for(int i=17;i>=0;i--)
        if(fa[a][i]!=fa[b][i])
            a=fa[a][i],b=fa[b][i];
    return fa[a][0];

 
int up(int u,int d)

    for(int i=17;i>=0;i--)
        if(d>=(1<<i))
            u=fa[u][i],d-=(1<<i);
    return u;

 
data getmid(int x,int y,int lca)

    int len=d[x]+d[y]-(d[lca]<<1);
    if(d[x]>=d[y]) return data(0,up(x,(len-1)>>1));
    return data(1,up(y,len>>1));

 
int query(int x,int y,int z,int xy,int xz)

    data ans1=getmid(x,y,xy),ans2=getmid(x,z,xz);
    if(!ans1.opt&&!ans2.opt)
    
        if(d[ans1.u]<d[ans2.u])
            swap(ans1,ans2);
        return size[ans1.u];
    
    else
    
        if(ans1.opt&&ans2.opt)
        
            if(d[ans1.u]<d[ans2.u])
                swap(ans1,ans2);
            if(lca(ans1.u,ans2.u)==ans2.u)
                return n-size[ans2.u];
            return n-size[ans2.u]-size[ans1.u];
        
        else
        
            if(ans1.opt)
                swap(ans1,ans2);
            if(lca(ans1.u,ans2.u)==ans1.u)
                return size[ans1.u]-size[ans2.u];
            return size[ans1.u];
        
    

 
int main()

    scanf("%d",&t);
    while(t--)
    
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        
            int u,v;
            scanf("%d%d",&u,&v);
            adde(u,v),adde(v,u);
        
        d[1]=1;
        dfs(1);
        scanf("%d",&m);
        while(m--)
        
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            int xy=lca(x,y),xz=lca(x,z),yz=lca(y,z);
            printf("%d %d %d\n",query(x,y,z,xy,xz),query(y,x,z,xy,yz),query(z,x,y,xz,yz));
        
    
    return 0;

以上是关于HDU4822XSY2021Tri-war的主要内容,如果未能解决你的问题,请参考以下文章

XSY2278HDU5669the Red Sun(线段树+dijkstra)

bzoj4822: [Cqoi2017]老C的任务

[BZOJ4822][Cqoi2017]老C的任务

luogu_P4822 [BJWC2012]冻结

p4822[BJWC2012]冻结

[BZOJ4822][CQOI2017]老C的任务(扫描线+树状数组)