P2801 教主的魔法 ——分块

教主的魔法

题目描述

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给 XMYZ 信息组每个英雄看。于是 \(N\) 个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为 \(1, 2, \ldots, N\)

每个人的身高一开始都是不超过 \(1000\) 的正整数。教主的魔法每次可以把闭区间 \([L, R]\)\(1≤L≤R≤N\))内的英雄的身高全部加上一个整数 \(W\)。(虽然 \(L=R\) 时并不符合区间的书写规范,但我们可以认为是单独增加第 \(L(R)\) 个英雄的身高)

CYZ、光哥和 ZJQ 等人不信教主的邪,于是他们有时候会问 WD 闭区间 \([L, R]\) 内有多少英雄身高大于等于 \(C\),以验证教主的魔法是否真的有效。

WD 巨懒,于是他把这个回答的任务交给了你。

输入格式

\(1\) 行为两个整数 \(N, Q\)\(Q\) 为问题数与教主的施法数总和。

\(2\) 行有 \(N\) 个正整数,第 \(i\) 个数代表第 \(i\) 个英雄的身高。

\(3\) 到第 \(Q+2\) 行每行有一个操作:

  1. 若第一个字母为 M,则紧接着有三个数字 \(L, R, W\)。表示对闭区间 \([L, R]\) 内所有英雄的身高加上 \(W\)

  2. 若第一个字母为 A,则紧接着有三个数字 \(L, R, C\)。询问闭区间 \([L, R]\) 内有多少英雄的身高大于等于 \(C\)

输出格式

对每个 A 询问输出一行,仅含一个整数,表示闭区间 \([L, R]\) 内身高大于等于 \(C\) 的英雄数。

样例 #1

样例输入 #1

5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4

样例输出 #1

2
3

提示

【输入输出样例说明】

原先 \(5\) 个英雄身高为 \(1, 2, 3, 4, 5\),此时 \([1, 5]\) 间有 \(2\) 个英雄的身高大于等于 \(4\)。教主施法后变为 \(1, 2, 4, 5, 6\),此时 \([1, 5]\) 间有 \(3\) 个英雄的身高大于等于 \(4\)

【数据范围】

对于 \(30\%\) 的数据,\(N≤1000\)\(Q≤1000\)

对于 \(100\%\) 的数据,\(N≤10^6\)\(Q≤3000\)\(1≤W≤1000\)\(1≤C≤10^9\)


\(\text{upd 2022.8.18}\):新增加一组 Hack 数据。
\(\text{upd 2023.8.16}\):新增加一组 Hack 数据

分析

分块。对原数组中的每一块排序后复制到新数组。

对于散块修改/询问暴力修改,整块重赋值。

对于整块修改/询问,打标记/二分。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,M=1e6+100;
struct edge{int y,n,x;}e[N<<1];
int n,head[N],cnt,deg[N];
int f[N][22],ans[N],q[N];
int fa[N],dep[N],chu[N],to[N],g[N];
void init()
{
    scanf("%d",&n);
    for(int i=1,x;i<=n;++i)
    {
        scanf("%d",&x);
        while(x!=0)// x-->i
        {
            ++deg[i];
            e[++cnt].n=head[x];
            e[cnt].y=i;
            head[x]=cnt;
            scanf("%d",&x);
        }
    }
}
int lca(int x,int y)
{
    if(x==y)return x;
    if(dep[x]<dep[y])swap(x,y);
    for(int i=18;i>=0;--i)
    {
        if(dep[f[x][i]]>dep[y])
            x=f[x][i];
    }
    if(dep[x]>dep[y])x=f[x][0];
    if(x==y)return x;
    for(int i=18;i>=0;--i)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
void work()
{
    int he=1,ta=0;
    for(int i=1;i<=n;++i)
    {
        if(deg[i]==0)
        {
            e[++cnt].n=head[n+1];
            e[cnt].y=i;
            head[n+1]=cnt;
            q[++ta]=i;
        }
        fa[i]=n+1;
    }
    while(he<=ta)
    {
        int u=q[he];
        ++he;
        for(int i=head[u];i;i=e[i].n)
        {
            int v=e[i].y;
            if(fa[v]==n+1)
                fa[v]=u;
            else
                fa[v]=lca(fa[v],u);
            --deg[v];
            if(deg[v]==0)
            {
                dep[v]=dep[fa[v]]+1;
                f[v][0]=fa[v];
                to[v]=fa[v];
                ++chu[fa[v]];
                for(int i=1;i<=18;++i)
                    f[v][i]=f[f[v][i-1]][i-1];
                q[++ta]=v;
            }
        }
    }

    he=1;
    ta=0;
    int num=0;
    for(int i=1;i<=n;++i)
    {
        g[i]=1;
        if(chu[i]==0)
            q[++ta]=i;
    }
    num=ta;
    while(he<=ta)
    {
        int u=q[he];
        ++he;
        g[to[u]]+=g[u];
        --chu[to[u]];
        if(chu[to[u]]==0)q[++ta]=to[u];
    }

    for(int i=1;i<=n;++i)
        printf("%d\n",g[i]-1);
}
int main()
{

    init();
    work();
    return 0;
}
posted @ 2024-11-29 11:22  Glowingfire  阅读(3)  评论(0编辑  收藏  举报