bzoj 5361: [Lydsy1805月赛]对称数 可持久化线段树

题意

给一棵树,点有点权,每次询问一条链上最小的出现偶数次的正整数。
n , m 200000

分析

按照套路,我们先给每个数随机一个unsigned long long范围内的权值,然后考虑二分答案,显然若位于 [ l , r ] 中的数的权值异或和等于区间内每个数权值的异或和,则区间中每个数都恰好出现奇数次,反之则存在某个数出现偶数次。
那么我们只要在树上建主席树,然后每次在主席树上二分即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef unsigned long long LL;

const int N=200005;

int n,m,sz,cnt,mx,last[N],fa[N],dep[N],top[N],size[N],col[N],rt[N];
LL val[N],s[N];
struct edge{int to,next;}e[N*2];
struct tree{int l,r;LL s;}t[N*20];

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void addedge(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

int newnode()
{
    sz++;t[sz].l=t[sz].r=t[sz].s=0;
    return sz;
}

void ins(int &d,int l,int r,int x)
{
    int p=d;d=newnode();t[d]=t[p];t[d].s^=val[x];
    if (l==r) return;
    int mid=(l+r)/2;
    if (x<=mid) ins(t[d].l,l,mid,x);
    else ins(t[d].r,mid+1,r,x);
}

void dfs1(int x)
{
    dep[x]=dep[fa[x]]+1;size[x]=1;
    rt[x]=rt[fa[x]];
    ins(rt[x],1,mx,col[x]);
    for (int i=last[x];i;i=e[i].next)
    {
        if (e[i].to==fa[x]) continue;
        fa[e[i].to]=x;
        dfs1(e[i].to);
        size[x]+=size[e[i].to];
    }
}

void dfs2(int x,int chain)
{
    top[x]=chain;int k=0;
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&size[e[i].to]>size[k]) k=e[i].to;
    if (k) dfs2(k,chain);
    for (int i=last[x];i;i=e[i].next)
        if (e[i].to!=fa[x]&&e[i].to!=k) dfs2(e[i].to,e[i].to);
}

int get_lca(int x,int y)
{
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

void clear()
{
    mx=sz=cnt=0;
    for (int i=1;i<=n;i++) last[i]=0;
}

int main()
{
    int T=read();
    for (int i=1;i<=200001;i++) val[i]=(LL)rand()*rand()*rand(),s[i]=s[i-1]^val[i];
    while (T--)
    {
        n=read();m=read();
        clear();
        for (int i=1;i<=n;i++) col[i]=read(),mx=std::max(mx,col[i]);
        mx++;
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read();
            addedge(x,y);
        }
        dfs1(1);dfs2(1,1);
        while (m--)
        {
            int x=read(),y=read(),lca=get_lca(x,y);
            int p1=rt[x],p2=rt[y],p3=rt[lca],p4=rt[fa[lca]],l=1,r=mx;
            while (l<r)
            {
                int mid=(l+r)/2;
                if ((t[t[p1].l].s^t[t[p2].l].s^t[t[p3].l].s^t[t[p4].l].s)==(s[mid]^s[l-1]))
                {
                    l=mid+1;
                    p1=t[p1].r;p2=t[p2].r;p3=t[p3].r;p4=t[p4].r;
                }
                else
                {
                    r=mid;
                    p1=t[p1].l;p2=t[p2].l;p3=t[p3].l;p4=t[p4].l;
                }
            }
            printf("%d\n",l);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33229466/article/details/80472437
今日推荐