4448: [Scoi2015]情报传递

本文介绍了一种使用主席树解决树链剖分问题的方法。通过对询问进行转换,利用主席树来高效地求解区间内特定条件的数值。文章提供了完整的C++代码实现,并详细解释了关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主席树维护树链剖分…
一开始直接套了个贪心的线段树…
发现t的没边了….这就很尴尬呀..
观察后发现可以把一个询问转换为寻求区间有多少小于i-c-1的数.
发现这个性质就很好,一个主席树可以很轻松的解决,那么套上就好啦.
c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}

const int N = 2e5 + 500;
int n,root,f[N],w[N],rt[N];
int head[N],nxt[N],to[N],tot;
bool vis[N];

struct Seg_tree
{
    int val[4000000],ls[4000000],rs[4000000],sz;
    void insert(int&x,int y,int l,int r,int p)
    {
        x = ++sz;
        val[x] = val[y];
        ls[x] = ls[y]; rs[x] = rs[y];
        ++val[x];
        if(l == r) return;
        int mid = l + r >> 1;
        if(p <= mid) insert(ls[x],ls[y],l,mid,p);
        else insert(rs[x],rs[y],mid+1,r,p);
    }

    int query(int x,int l,int r,int p)
    {
        if(r <= p) return val[x];
        int mid = l + r>> 1;
        if(p > mid) return val[ls[x]] + query(rs[x],mid+1,r,p);
        else return query(ls[x],l,mid,p);
    }
}seg;

inline void add(int x,int y)
{
    to[tot] = y;
    nxt[tot] = head[x];
    head[x] = tot++;
}

int deep[N],size[N],hson[N],top[N],id[N],idx[N],sz;
void dfs1(int x)
{
    size[x] = 1;
    for(register int i = head[x] ;~i;i = nxt[i])
    {
        deep[to[i]] = deep[x] + 1;
        dfs1(to[i]);
        size[x] += size[to[i]];
        if(size[to[i]] > size[hson[x]])
            hson[x] = to[i];

    }
}

void dfs2(int x,int t)
{
    top[x] = t;
    id[x] = ++ sz;idx[sz] = x;
    if(hson[x]) dfs2(hson[x],t);
    for(register int i = head[x];~i;i=nxt[i])
        if(to[i] != hson[x])
            dfs2(to[i],to[i]);
}

int find(int x,int y)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        ans += deep[x] - deep[top[x]] + 1;
        x = f[top[x]];
    }
    if(deep[x] < deep[y]) swap(x,y); 
    return ans + deep[x] - deep[y] + 1;
}

int query(int x,int y,int c)
{
    if(c < 1) return 0;
    int ans = 0;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        ans += seg.query(rt[id[x]],1,N,c) - seg.query(rt[id[top[x]] - 1],1,N,c);
        x = f[top[x]];
    }
    if(deep[x] < deep[y]) swap(x,y); 
    return ans + seg.query(rt[id[x]],1,N,c) - seg.query(rt[id[y] - 1],1,N,c);
} 

int u[N],v[N],ti[N];

int main()
{
    memset(head,-1,sizeof head);
    read(n);
    rep(i,1,n)
    {
        read(f[i]);
        if(f[i]) add(f[i],i);
        else root = i;
    }

    dfs1(root);
    dfs2(root,root);

    rep(i,1,n) w[i] = N ;
    int q;
    read(q);
    rep(i,1,q)
    {
        int op,a;
        read(op);
        if(op == 1)
        {
            read(u[i]); read(v[i]); read(ti[i]);
            ti[i] = i - ti[i] - 1;
        }
        else
        {   
            read(a);
            if(vis[a]) continue;
            vis[a] = 1; w[a] = i;
        }
    }

    rep(i,1,n) seg.insert(rt[i],rt[i-1],1,N,w[idx[i]]);
    rep(i,1,q) if(u[i]) printf("%d %d\n",find(u[i],v[i]),query(u[i],v[i],ti[i]));

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值