bzoj 3211: 花神游历各国 树状数组+并查集
2016-11-24 21:52
417 查看
题意
给出n个数,要求资瓷下列操作:1 l r表示查询l到r的和
2 l r表示把每个a[x] (l<=x<=r)变为sqrt(x)
n<=100000,m<=200000
分析
显然开根号是不能区间维护的,但发现一个int最多开五次根号就会变为1,所以我们可以用并查集来维护每个数的下一个可以开根号的数是哪一个,那么就可以均摊O(1)来暴力修改了。区间操作用树状数组搞定即可。
第一次写并查集维护指针,写的很不熟练,最后还是去看了一发标才写出来。其实就是每个f[i]记录最小的j满足j>=i且a[j]>1.
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define N 100005 #define ll long long using namespace std; int n,m,a ,f ; ll c ; void ins(int x,int y) { while (x<=n) { c[x]+=y; x+=x&(-x); } } ll query(int x) { ll ans=0; while (x) { ans+=c[x]; x-=x&(-x); } return ans; } int find(int x) { if (f[x]==x) return x; f[x]=find(f[x]); return f[x]; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); ins(i,a[i]); } for (int i=1;i<=n+1;i++) f[i]=i; for (int i=1;i<=n;i++) if (a[i]<=1) f[find(i)]=find(i+1); scanf("%d",&m); for (int i=1;i<=m;i++) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if (op==1) { printf("%lld\n",query(r)-query(l-1)); }else { if (a[l]<=1) l=find(l+1); while (l<=r) { ins(l,-a[l]); a[l]=sqrt(a[l]); ins(l,a[l]); if (a[l]<=1) f[find(l)]=find(l+1); l=find(l+1); } } } return 0; }
相关文章推荐
- BZOJ 3211 花神游历各国 树状数组+并查集
- BZOJ 3211 花神游历各国 树状数组+并查集
- BZOJ 3211: 花神游历各国/BZOJ 3038: 上帝造题的七分钟2 树状数组+并查集
- BZOJ 3211 花神游历各国 (树状数组+并查集)
- BZOJ3211 花神游历各国(树状数组+并查集)
- BZOJ[3211]花神游历各国 树状数组+并查集
- [BZOJ3211]花神游历各国&&[BZOJ3038] 上帝造题的七分钟2 树状数组+并查集
- codevs2492 上帝造题的七分钟2 BZOJ3211 花神游历各国
- [BZOJ3211] 花神游历各国/[BZOJ3038] 上帝造题的七分钟2
- BZOJ 3038 上帝造题的七分钟2 BZOJ 3211 花神游历各国 题解
- 【BZOJ】【3211】花神游历各国
- bzoj3211花神游历各国 线段树
- BZOJ3211 花神游历各国 线段树+并查集
- 【bzoj3211】花神游历各国
- 【线段树/区间开平方】BZOJ3211-花神游历各国
- [BZOJ3211][SPOJ2713][线段树]GSS 4(花神游历各国)[一般题]
- BZOJ3038 && BZOJ3211 上帝造题的七分钟2 && 花神游历各国 (线段树 + 开方标记)
- 【bzoj3211】【花神游历各国】【线段树+并查集】
- 【BZOJ3211】【花神游历各国】&【BZOJ3038】上帝造题的七分钟2(树状数组+链表)
- bzoj3211: 花神游历各国&&3038: 上帝造题的七分钟2