漂亮的公园(LCA+思维)

符合条件的整数

https://ac.nowcoder.com/acm/contest/5902/A

题目描述
一棵树,每个节点有一个颜色,q个询问
每次询问x,y
求树上距离最长的两点
其中一点color【i】=x;
另外一点color【i】=y;
思路
1.对于求树上两点之间的距离可以用lca,
倍增法求lca也不再介绍
2.求max(color[i],color[j]]
如果只看一种颜色x求最长的距离可以枚举是x颜色的每个点
我们暂且叫颜色x的直径
如果看两种颜色x,y 那么max是x直径的两端点中的其中一点和y直径中两端点中的其中一点

由于color[i]比较大要可以先离散化
代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define UpMing main
#define re register
#pragma GCC optimize(2)
#define Accept return 0;
#define lowbit(x) ((x)&(-(x)))
#define mst(x, a) memset( x,a,sizeof(x) )
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
typedef pair PII;
typedef unsigned long long ull;
const int inf =0x3f3f3f3f;
const int maxn=4e5+66;
const ll mod = 1e9+7;
const int N =1e6+3;
inline ll read() {
    ll  x=0;
    bool f=0;
    char ch=getchar();
    while (ch<'0'||'9'<ch)    f|=ch=='-', ch=getchar();
    while ('0'<=ch && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
void out(ll x) {
    int stackk[20];
    if(x<0) {
        putchar('-');
        x=-x;
    }
    if(!x) {
        putchar('0');
        return;
    }
    int top=0;
    while(x) stackk[++top]=x%10,x/=10;
    while(top) putchar(stackk[top--]+'0');
}
int  n,q,a[maxn],b[maxn],fa[200002][200],len,depth[maxn];
vectorv[maxn],c[maxn];
void dfs(int  t,int  p) {
    depth[t]=depth[p]+1;
    fa[t][0]=p;
    for(int i=1 ; i<=len; i++) fa[t][i]=fa[fa[t][i-1]][i-1];
    for(auto u:v[t]) {
        if(u==p) continue;
        dfs(u,t);
    }
}
int lca(int  x,int  y) {
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=len ; i>=0 ; i--) {
        if(depth[fa[x][i]]>=depth[y])
            x=fa[x][i];
    }
    if(x==y) return x;
    for(int i=len; i>=0 ; i--) {
        ll dx=fa[x][i];
        ll dy=fa[y][i];
        if(dx!=dy) x=dx,y=dy;
    }
    return fa[x][0];
}
int  dis(int  x,int  y) {
    return depth[x]+depth[y]-2*depth[lca(x,y)];
}
mapmp;
int UpMing() {
    n=read();
    q=read();
    len=log2(n)+1;
    for(int i=1 ; i<=n ; i++)
        a[i]=read(),b[i]=a[i],mp[a[i]]++;
    sort(b+1,b+1+n);
    ll pos=unique(b+1,b+1+n)-(b+1);
    for(int i=1 ; i<=n ; i++) {
        a[i]=lower_bound(b+1,b+1+pos,a[i])-b;
        c[a[i]].push_back(i);
    }
    for(int i=1 ; i<n ; i++) {
        ll x=read();
        ll y=read();
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(1,0);
    for(int i=1 ; i<=pos; i++) {
        for(int j=0 ; j<c[i].size(); j++) {
            ll dis1=dis(c[i][0],c[i][j]);
            ll dis2=dis(c[i][1],c[i][j]);
            ll dis3=dis(c[i][0],c[i][1]);
            if(dis1>dis3&&dis2>dis3) {
                if(dis1>dis2)  c[i][1]=c[i][j];
                else c[i][0]=c[i][j];
            } else if(dis1>dis3) c[i][1]=c[i][j];
            else if(dis2>dis3) c[i][0]=c[i][j];
        }
    }
    while(q--) {
        ll x=read();
        ll y=read();
        if(mp[x]==0||mp[y]==0) {
            printf("0\n");
            continue;
        }
        x=lower_bound(b+1,b+1+pos,x)-b;
        y=lower_bound(b+1,b+1+pos,y)-b;
        ll dis1=0;
        ll dis2=0;
        ll dis3=0;
        ll dis4=0;
        dis1=dis(c[x][0],c[y][0]);
        if(c[x].size()>1&&c[y].size()>1) {
            dis4=dis(c[x][1],c[y][1]);
            dis3=dis(c[x][0],c[y][1]);
            dis2=dis(c[x][1],c[y][0]);
        } else if(c[y].size()>1)
            dis3=dis(c[x][0],c[y][1]);
        else if(c[x].size()>1)
            dis2=dis(c[x][1],c[y][0]);
        out(max(max(max(dis4,dis3),dis1),dis2));
        printf("\n");
    }
    Accept;
}
全部评论

相关推荐

球球别再泡了:坏,我单9要了14
点赞 评论 收藏
分享
Java抽象带篮子:安卓怎么你了
投递荣耀等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务