题目链接
登录—专业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=lrai ,即经文响度之和。
其中,响子再次朗诵经文的操作 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;
}