花神游历各国
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
这题好风骚的操作……
思路:
考虑到sqrt貌似没有什么办法维护,咱选择树状数组。
修改暴力就好,求和上树状数组。
然而修改暴力显然会出事。
但可以注意到,一个1e9以内的数sqrt不超过6次sqrt后就会变成1。
那么维护一个并查集,如果一个数为0或1,就把它合并到它右边的节点上。
然后在修改时就可以用并查集快速忽略所有操作后无变化的数了。
还有这种操作???
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll read()
{
ll x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
inline bool chkmax(ll &a,ll b){if(a<b){a=b;return 1;}return 0;}
inline int lolbit(int x){return x&(-x);}
const int N=100009;
ll n,m,bit[N],fa[N],a[N];
inline void modify(int pos,ll val)
{
while(pos<=n)
{
bit[pos]+=val;
pos+=lolbit(pos);
}
}
inline ll query(int pos)
{
ll ret=0;
while(pos)
{
ret+=bit[pos];
pos-=lolbit(pos);
}
return ret;
}
inline int find(int x)
{
if(!fa[x] || fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int main()
{
n=read();
for(int i=1,v;i<=n;i++)
{
modify(i,a[i]=read());
if(a[i]<=1)
fa[i]=i+1;
}
m=read();
for(int i=1,x,l,r;i<=m;i++)
{
x=read();
l=read();
r=read();
if(x==1)
printf("%lld\n",query(r)-query(l-1));
else
{
for(int j=l;j<=r;j=find(j+1))
{
ll tmp=sqrt(a[j]);
modify(j,tmp-a[j]);
a[j]=tmp;
if(tmp<=1)
fa[j]=find(j+1);
}
}
}
return 0;
}