響符「パワーレゾナンス」 并查集+树状数组

题目链接

登录—专业IT笔试面试备考平台_牛客网


幽谷响子最近在妖怪之山中依靠回声朗诵经文。
她事先已经朗诵过 nnn 篇经文,其中第 iii 篇经文回声的响度为 aia_iai​ 。由于城管正在妖怪之山泡温泉,因而她计划在执行完 qqq 次操作后立刻离开。

响子酱的操作有以下两种:

  • 1 l r1\ l\ r1 l r :表示响子酱根据所有满足 l≤i≤rl \le i \le rl≤i≤r 的经文回声响度 aia_iai​ ,再次进行朗诵,即 ai=F(ai)a_i = F(a_i)ai​=F(ai​) ;
  • 2 l r2\ l\ r2 l r :表示响子酱接收所有满足 l≤i≤rl \le i \le rl≤i≤r 的的经文响度 aia_iai​ 后,在本子上记录下一行,一行只有一个数字,表示 ∑i=lrai\sum_{i=l}^{r} a_i∑i=lr​ai​ ,即经文响度之和。

其中,响子再次朗诵经文的操作 F(x)F(x)F(x) 表示如下。
F(x)=2⌊∣x3−3x∣3x2+1⌋F(x) = 2 \bigg\lfloor \cfrac{ |x^3 - 3x| }{3 x^2 + 1} \bigg\rfloorF(x)=2⌊3x2+1∣x3−3x∣​⌋

其中 ⌊x⌋\lfloor x \rfloor⌊x⌋ 为向下取整,即 ⌊1.9⌋=1,⌊2⌋=2\lfloor 1.9 \rfloor = 1, \lfloor 2 \rfloor = 2⌊1.9⌋=1,⌊2⌋=2 。

在响子执行完 q 次操作以后,她在本子上记录的内容是什么呢?

思路

对于  ,如果暴力验证的话,不难发现,在 [0,106] 范围内的数字最多需要执行 32 次操作,就会归 0 ,因此需要优化操作 1 的执行效率,使用并查集优化。然后查询区间和可以用树状数组优化

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 1e5 + 10;
ll a[maxn],c[maxn],fa[maxn];
int n,q;

int lowbit(int i)
{
    return i & (-i);
}
ll query(int x)
{
    ll sum = 0;
    for (int i = x; i > 0; i -= lowbit(i))
    {
        sum += c[i];
    }
    return sum;
}
ll query(int l,int r)
{
    return query(r)-query(l-1);
}
void update(int x, ll add)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        c[i] += add;
    }
}

ll f(ll x)
{
    return 1LL*2*(abs(x*x*x-3*x)/(3*x*x+1));
}

ll find(ll x)
{
    while(x!=fa[x])
    {
        x=fa[x];
    }
    return x;
}
void merge(int from,int to)
{
    fa[find(from)]=find(to);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);//这三句话一定要有,不然就超时了,亲测

    cin >> n >> q;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        update(i,a[i]);
        fa[i]=i;
    }
    while (q--)
    {
        int op, l, r;
        cin >> op >> l >> r;
        if (op == 1)
        {
            for (int i = l; i <= r; i=find(i)+1)//使用并查集维护数组,直接跳过那些已经变为0的数字
            {
                if(a[i]==0)
                {
                    merge(i-1,i);
                }
                else{
                    ll date=f(a[i])-a[i];
                    update(i,date);
                    a[i]+=date;
                }
            }
        }
        else
        {
            cout<<query(l,r)<<'\n';
        }
    }
    return 0;
}

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值