倍增板子整理

LCA(最近公共祖先)(复杂度:O(log(n))

ll heads[maxn], fa[maxn][30], wei[maxn][30];
ll dep[maxn], vis[maxn];

struct Edge1
{
    ll u, v,w, next;
} edges1[maxm];

void add(ll u, ll v, ll w)
{
    edges1[++tot].next = heads[u];
    edges1[tot].u = u;
    edges1[tot].v = v;
    edges1[tot].w = w;
    heads[u] = tot;
}

ll fd(ll x)
{
    if (f[x] == x)
        return x;
    return f[x] = fd(f[x]);
}

void dfs(ll now, ll fath)
{
    vis[now] = 1;
    fa[now][0] = fath;
    dep[now] = dep[fath] + 1;
    for (ll i = heads[now]; i; i = edges1[i].next)
    {
        ll v = edges1[i].v;
        ll w = edges1[i].w;
        if (v == fath)
        {
            continue;
        }
        wei[v][0] = w;
        dfs(v, now);
    }
}

ll LCA(ll x, ll y)
{
    if (fd(x) != fd(y))
        return -1;
    if (dep[x] > dep[y])
    {
        swap(x, y);
    }
    ll ans = INF;
    for (ll i = 22; i >= 0; i--)
    {
        if (dep[x] <= dep[y] - (1 << i))
        {
            ans = min(ans, wei[y][i]);
            y = fa[y][i];
        }
    }
    // printf("%lld\n",ans);
    if (x == y)
        return ans;
    for (ll i = 22; i >= 0; i--)
    {
        if (fa[x][i] != fa[y][i])
        {
            ans = min(ans, wei[x][i]);
            ans = min(ans, wei[y][i]);
            x = fa[x][i], y = fa[y][i];
        }
    }
    ans = min(ans, min(wei[x][0], wei[y][0]));
    return ans;
}

int main()
{
    // debug;
    scanf("%lld%lld", &n, &m);
    for (ll i = 0; i <= n; i++)
    {
        f[i] = i;
    }
    for (ll i = 1; i <= n; i++)
    {
        // printf("!\n");
        if (!vis[i])
        {
            dfs(i, 0);
            fa[i][0] = i;
            wei[i][0] = INF;
        }
    }
    for (ll i = 1; i <= 22; i++)
    {
        for (ll j = 1; j <= n; j++)
        {
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
            wei[j][i] = min(wei[j][i - 1], wei[fa[j][i - 1]][i - 1]);
        }
    }
    scanf("%lld", &q);
    while (q--)
    {
        ll x, y;
        scanf("%lld%lld", &x, &y);
        printf("%lld\n", LCA(x, y));
    }
}

ST表

ll arr[arrn][21],n,m,l,r;//arr[i][j]表示,从i位置开始的2^j个数中的最大值,例如arr[i][1]表示的是i位置和i+1位置中两个数的最大值

ll query(ll l,ll r)
{
    ll k=log2(r-l+1);
    return max(arr[l][k],arr[r-(1<<k)+1][k]);
}

int main()
{
    n=read();m=read();//n,m表示数组元素个数,询问次数
    for(ll i=1;i<=n;i++) arr[i][0]=read();
    for(ll j=1;j<=21;j++)//注意i,j顺序
    {
        for(ll i=1;i+(1<<j)-1<=n;i++)
        {
            arr[i][j]=max(arr[i][j-1],arr[i+(1<<(j-1))][j-1]);
        }
    }
    for(ll i=1;i<=m;i++)
    {
        l=read();r=read();
        printf("%lld\n",query(l,r));
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值