【JZOJ4587】Snow的追寻

来源:互联网 发布:js获取ios系统版本 编辑:程序博客网 时间:2024/06/10 20:19

Description

这里写图片描述

Solution

一道很裸的题目,51Nod上有一个加强版的叫树中最远点对。

思路

有对子树限制的就想一想dfs序。然后在dfs序上建一个线段树每个点存储它表示的点集的最长距离和对应的两个点,合并的时候有六种情况,两个子树的两个点两两配对,然后再与这两个点的值比较,一共六种。
最后查询的时候,限制的两棵子树在dfs序上,分成了三个区间,这三个区间分别询问就好了。

Code

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;const int maxn=100007;int first[maxn*2],next[maxn*2],last[maxn*2],num;int i,j,k,l,n,m,q,da,da1,mx,mx1,dfn,wei[maxn],p[maxn],hou[maxn];int d[maxn],deep[maxn],f[maxn][20];bool bz[maxn];struct node{    int sum,yi,er;}t[maxn*3],ans;void add(int x,int y){    last[++num]=y;next[num]=first[x];first[x]=num;}void dfs(int x,int y){    int i;    wei[x]=++dfn;p[dfn]=x;f[x][0]=y;deep[x]=deep[y]+1;    rep(i,x){        if(last[i]!=y){            dfs(last[i],x);        }    }    hou[x]=dfn;}int lca(int x,int y){    int i,z=0;if(deep[x]<deep[y])swap(x,y);    fod(i,19,0)if(deep[f[x][i]]>deep[y])x=f[x][i];    if(deep[x]>deep[y])x=f[x][0];    fod(i,19,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];    if(x!=y)return f[x][0];return x;}int ju(int x,int y){    if(!x||!y)return 0;    int z=lca(x,y);    return deep[x]+deep[y]-2*deep[z];}void merge(node &x,node y,node z){    int a,b,c,d,e,f;    a=ju(y.yi,z.yi);b=ju(y.yi,z.er);c=ju(y.er,z.yi);d=ju(y.er,z.er);    e=max(a,max(b,max(c,d)));    if(!(e-a))x.yi=y.yi,x.er=z.yi,x.sum=a;if(!(e-b))x.yi=y.yi,x.er=z.er,x.sum=b;    if(!(e-c))x.yi=y.er,x.er=z.yi,x.sum=c;if(!(e-d))x.yi=y.er,x.er=z.er,x.sum=d;    if(y.sum>x.sum)x.yi=y.yi,x.er=y.er,x.sum=y.sum;    if(z.sum>x.sum)x.yi=z.yi,x.er=z.er,x.sum=z.sum;    if(!x.sum)x.yi=x.er=0;}void build(int x,int l,int r){    if(l==r){        t[x].yi=t[x].er=p[l];return;    }    int mid=(l+r)/2;    build(x*2,l,mid);build(x*2+1,mid+1,r);    merge(t[x],t[x*2],t[x*2+1]);}void find(int x,int l,int r,int y,int z){    if(y>z)return;    if(l==y&&r==z){        merge(ans,ans,t[x]);return;    }    int mid=(l+r)/2;    if(z<=mid)find(x*2,l,mid,y,z);    else if(y>mid)find(x*2+1,mid+1,r,y,z);    else{        find(x*2,l,mid,y,mid);        find(x*2+1,mid+1,r,mid+1,z);    }}int main(){    freopen("snow.in","r",stdin);    freopen("snow.out","w",stdout);    scanf("%d%d",&n,&q);    fo(i,1,n-1){        scanf("%d%d",&k,&l);        add(k,l);add(l,k);    }    dfs(1,0);    fo(j,1,19){        fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1];    }    build(1,1,n);    for(;q;q--){        scanf("%d%d",&k,&l);        if(k==1||l==1){            printf("0\n");            continue;        }        if(wei[k]>wei[l])swap(k,l);        ans.sum=ans.yi=ans.er=0;        find(1,1,n,1,wei[k]-1);        find(1,1,n,hou[k]+1,wei[l]-1);        if(hou[k]>=hou[l])find(1,1,n,hou[k]+1,n);        else find(1,1,n,hou[l]+1,n);        printf("%d\n",ans.sum);    }}
1 0
原创粉丝点击