BZOJ.3757.苹果树(树上莫队)

Posted SovietPower

tags:

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

题面链接

/*
代码正确性不保证。。
在DFS序做莫队 
当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 
*/
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=4e5+5,M=1e5+5;

int n,m,size,Enum,H[N],nxt[N<<1],to[N<<1],dep[N],fa[N],top[N],son[N],sz[N];
int Now,Ans[M],seq[N<<1],in[N],out[N],id,A[N],tm[N];
bool vis[N];
struct Ques
{
    int l,r,lca,id,x,y;
    bool operator <(const Ques &a)const{
        return l/size<a.l/size?r<a.r:l/size<a.l/size;
    }
}q[M];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline void AddEdge(int u,int v)
{
    to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void Pre_DFS(int x)
{
    in[x]=++id, seq[id]=x, sz[x]=1;
    int mx=0;
    for(int v,i=H[x]; i; i=nxt[i])
        if((v=to[i])!=fa[x])
        {
            fa[v]=x, dep[v]=dep[x]+1, Pre_DFS(v), sz[x]+=sz[v];
            if(sz[v]>mx) mx=sz[v],son[x]=v;
        }
    out[x]=++id, seq[id]=x;
}
void DFS2(int x,int tp)
{
    top[x]=tp;
    if(son[x])
    {
        DFS2(son[x],tp);
        for(int i=H[x]; i; i=nxt[i])
            if(to[i]!=fa[x]&&to[i]!=son[x])
                DFS2(to[i],to[i]);
    }
}
int Query_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]?y:x;
}
void Calc(int p)
{
    if(vis[p])
        if(!--tm[A[p]]) --Now;
        else ;
    else if(++tm[A[p]]==1) ++Now;
    vis[p]^=1;
}

int main()
{
    n=read(),m=read(),size=sqrt(n<<1);
    for(int i=1; i<=n; ++i) A[i]=read();
    for(int u,v,i=1; i<=n; ++i) u=read(),v=read(),AddEdge(u,v);
    Pre_DFS(0), DFS2(0,0);
    for(int u,v,w,i=1; i<=m; ++i)
    {
        u=read(),v=read(),w=Query_LCA(u,v),q[i].x=read(),q[i].y=read();
        if(in[u]>in[v]) std::swap(u,v);
        if(w==u) q[i].l=in[w],q[i].r=in[v],q[i].lca=0;
//      else if(w==v) q[i].r=in[w],q[i].r=in[u],q[i].lca=0;
        else q[i].l=out[u],q[i].r=in[v],q[i].lca=w;
        q[i].id=i;
    }
    std::sort(q+1,q+1+m);
    tm[0]=N;
    for(int l=1,r=0,i=1; i<=m; ++i)
    {
        while(l<q[i].l) Calc(seq[l++]);
        while(l>q[i].l) Calc(seq[--l]);
        while(r<q[i].r) Calc(seq[++r]);
        while(r>q[i].r) Calc(seq[r--]);
        if(q[i].lca) Calc(q[i].lca);
        if(tm[q[i].x]&&tm[q[i].y]&&q[i].x&&q[i].y) Ans[q[i].id]=Now-1;
        else Ans[q[i].id]=Now;
        if(q[i].lca) Calc(q[i].lca);
    }
    for(int i=1; i<=m; ++i) printf("%d\n",Ans[i]);

    return 0;
}

以上是关于BZOJ.3757.苹果树(树上莫队)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3757 苹果树

bzoj3757 苹果树

BZOJ - 3757 树上莫队解决离线路径问题 & 学习心得

Bzoj3757 苹果树

SPOJ.COT2 Count on a tree II(树上莫队)

Nowcoder挑战赛39F(模板树上莫队)