【Codeforces226E】Noble Knight's Path

大概题意:
求树上两点间路径上第num次事件后第k个没有打过标记的点(保证一个点最多被标记一次)。

显然只需要树链剖分套主席树即可,查询k个点时先跳重链在二分(也可以在主席树上直接找),询问复杂度 O(log2n) ,打标记复杂度 O(logn)

#include <bits/stdc++.h>
#define gc getchar()
#define mid (l+r>>1)
#define N 100009
using namespace std;
int n,Q,first[N],number,size[N],fa[N],Mson[N],top[N],dfn[N],cnt;
int deep[N],val[N],ans,rt,root[N],lson[N<<6],rson[N<<6],sum[N<<6];
int pos[N],q[N];
struct edge
{
    int to,next;
    void add(int x,int y)
    {
        to=y,next=first[x],first[x]=number;
    }
}e[N<<1];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return s*x;
}
void dfs(int x)
{
    size[x]=1;
    deep[x]=deep[fa[x]]+1;
    for (int i=first[x];i;i=e[i].next)
    {
        fa[e[i].to]=x;
        dfs(e[i].to);
        size[x]+=size[e[i].to];
        if (size[e[i].to]>size[Mson[x]]) Mson[x]=e[i].to;
    }
}
void Dfs(int x,int y)
{
    top[x]=y;
    pos[dfn[x]=++cnt]=x;
    if (Mson[x]) Dfs(Mson[x],y);
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=Mson[x]) Dfs(e[i].to,e[i].to);
}
void ins(int &cur,int l,int r,int x,int last)
{
    cur=++cnt;
    lson[cur]=lson[last];
    rson[cur]=rson[last];
    sum[cur]=sum[last]+1;
    if (l==r) return;
    if (x<=mid) ins(lson[cur],l,mid,x,lson[last]);
    else ins(rson[cur],mid+1,r,x,rson[last]);
}
int qry(int cur1,int cur2,int l,int r,int L,int R)
{
    if (L>R) return 0;
    if (L<=l&&R>=r) return sum[cur2]-sum[cur1];
    int ret=0;
    if (L<=mid) ret+=qry(lson[cur1],lson[cur2],l,mid,L,R);
    if (R>mid) ret+=qry(rson[cur1],rson[cur2],mid+1,r,L,R);
    return ret;
}
int lca(int x,int y)
{
    for (;top[x]!=top[y];x=fa[top[x]])
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
    return deep[x]<deep[y]?x:y;
}
int qry(int x,int y,int k,int year,int now)
{
    int z=lca(x,y);
    for (;deep[top[x]]>deep[z];x=fa[top[x]])
    {
        int tmp=dfn[x]-dfn[top[x]]+1-qry(root[year],root[now],1,n,dfn[top[x]],dfn[x]);
        if (tmp>=k)
        {
            int l=dfn[top[x]],r=dfn[x],ret=0;
            while (l<=r)
            {
                int temp=dfn[x]-mid+1-qry(root[year],root[now],1,n,mid,dfn[x]);
                if (temp>=k) ret=mid,l=mid+1;
                else r=mid-1;
            }
            if (pos[ret]==y) return -1;
            return pos[ret];
        }
        else k-=tmp;
    }
    int tmp=dfn[x]-dfn[z]+1-qry(root[year],root[now],1,n,dfn[z],dfn[x]);
    if (tmp>=k)
    {
        int l=dfn[z],r=dfn[x],ret=0;
        while (l<=r)
        {
            int temp=dfn[x]-mid+1-qry(root[year],root[now],1,n,mid,dfn[x]);
            if (temp>=k) ret=mid,l=mid+1;
            else r=mid-1;
        }
        if (pos[ret]==y) return -1;
        return pos[ret];
    }
    else k-=tmp;
    int yy=y;
    int num=0;
    for (;deep[top[yy]]>deep[z];yy=fa[top[yy]])
        q[++num]=yy;
    tmp=dfn[yy]-dfn[z]-qry(root[year],root[now],1,n,dfn[z]+1,dfn[yy]);
    if (tmp>=k)
    {
        int l=dfn[z]+1,r=dfn[yy],ret=0;
        while (l<=r)
        {
            int temp=mid-dfn[z]-qry(root[year],root[now],1,n,dfn[z]+1,mid);
            if (temp>=k) ret=mid,r=mid-1;
            else l=mid+1;
        }
        if (pos[ret]==y) return -1;
        return pos[ret];
    }
    else k-=tmp;
    for (int i=num;i;i--)
    {
        int tmp=dfn[q[i]]-dfn[top[q[i]]]+1-qry(root[year],root[now],1,n,dfn[top[q[i]]],dfn[q[i]]);
        if (tmp>=k)
        {
            int l=dfn[top[q[i]]],r=dfn[q[i]],ret=0;
            while (l<=r)
            {
                int temp=mid-dfn[top[q[i]]]+1-qry(root[year],root[now],1,n,dfn[top[q[i]]],mid);
                if (temp>=k) ret=mid,r=mid-1;
                else l=mid+1;
            }
            if (pos[ret]==y) return -1;
            return pos[ret];
        }
        else k-=tmp;
    }
    return -1;
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++)
    {
        fa[i]=read();
        if (fa[i]==0) rt=i;
        e[++number].add(fa[i],i);
    }
    dfs(rt);
    Dfs(rt,rt);
    cnt=0;
    Q=read();
    for (int i=1;i<=Q;i++)
    {
        int op=read();
        if (op==1)
        {
            int x=read();
            val[x]=i;
            ins(root[i],1,n,dfn[x],root[i-1]);
        }
        else
        {
            root[i]=root[i-1];
            int x=read(),y=read(),k=read(),year=read();
            if (val[x]<=year) k++;
            printf("%d\n",qry(x,y,k,year,i));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值