P4216 [SCOI2015] 情报传递

P4216 [SCOI2015] 情报传递

题意简述:给你一棵树,在每个时刻可能将某个点点亮,或者做一次查询,询问x->y路径上有多少点是在当前时间k秒前点亮的

Solution:

这让我们很难不想到主席树:

每个节点建一颗主席树,维护根节点到此节点路径上在某个时间段内被点亮的点的个数(即以时间为x轴,点的个数为权值建树)

然后将所有操作离线,按照从浅到深(先父后子)建立主席树,然后对于每次查询(x,y)查询
t[x]+t[y]-t[lca]-t[fa_lca]这颗主席树上在[1,i-k-1]
(原题的k是不被包含的,但我线段树维护的闭区间)

然后这题就做完了
疑似我写过的最短紫题总结

Code:

#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
struct Tree{
    int ls,rs,num;
}t[N*80];
int n,m,cnt,tot;
void insert(int &x,int y,int l,int r,int val)
{
    t[x=++cnt]=t[y];
    t[x].num++;
    if(l==r)
    {
        return ;
    }
    int mid=l+r>>1;
    if(val<=mid)insert(t[x].ls,t[y].ls,l,mid,val);
    if(mid<val) insert(t[x].rs,t[y].rs,mid+1,r,val);
}
void query(int x,int y,int lca,int lca_fa,int l,int r,int L,int R,int &res)
{
    if(R<l||r<L)return;
    if(L<=l&&r<=R)
    {
        res+=t[x].num+t[y].num-t[lca].num-t[lca_fa].num;
        return ;
    }
    int mid=l+r>>1;
    if(L<=mid) query(t[x].ls,t[y].ls,t[lca].ls,t[lca_fa].ls,l,mid,L,R,res);
    if(mid<R)query(t[x].rs,t[y].rs,t[lca].rs,t[lca_fa].rs,mid+1,r,L,R,res);
}
int dep[N],fa[N][25],rt[N],tim[N];
vector<int> E[N];
void dfs(int x,int f)
{
    dep[x]=dep[f]+1;
    fa[x][0]=f;
    if(tim[x])insert(rt[x],rt[f],1,m,tim[x]);
    else rt[x]=rt[f];
    for(int i=1;i<=20;i++)
    {
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int i=0;i<E[x].size();i++)
    {
        int to=E[x][i];
        if(to==f)continue;
        dfs(to,x);
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;~i;i--)
    {
        if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
    }
    if(x==y)return x;
    for(int i=20;~i;i--)
    {
        if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    }
    return fa[x][0];
}
struct task{
    int opt,x,y,k;
}q[N];
struct add{
    int x,tim,dep;
    bool operator<(const add &a)const{
        return dep<a.dep;
    }
}e[N];
void work()
{
    cin>>n;
    for(int i=1,x;i<=n;i++)
    {
        scanf("%d",&x);
        E[x].push_back(i);
        E[i].push_back(x);
    }
    cin>>m;
    for(int i=1,opt,x,y,k;i<=m;i++)
    {
        scanf("%d%d",&opt,&x);
        if(opt==1)
        {
            scanf("%d%d",&y,&k);
        }
        else
        {
            tim[x]=i;
        }
        q[i]=(task){opt,x,y,k};
    }
    dfs(1,0);
    for(int i=1,x,y,k;i<=m;i++)
    {
        if(q[i].opt==1)
        {
            x=q[i].x,y=q[i].y,k=q[i].k+1;
            int lca=LCA(x,y),ans=0;           query(rt[x],rt[y],rt[lca],rt[fa[lca][0]],1,m,1,i-k,ans);
            printf("%d %d\n",dep[x]+dep[y]-dep[lca]*2+1,ans);
        }
    }
    return ;
}
int main()
{
    //freopen("P4216.in","r",stdin);freopen("P4216.out","r",stdout);
    work();
    return 0;
}
posted @ 2024-12-06 11:55  liuboom  阅读(11)  评论(0)    收藏  举报