刚开始做的时候用线段树做的,然后就跳进坑里了……因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了。然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉……没想到啊!
因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了。树状数组更新的时候就把其更新的差更新即可,太机智了这题……
昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕……
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #define PI acos(-1.0) #define mem(a,b) memset(a,b,sizeof(a)) #define sca(a) scanf("%d",&a) #define sc(a,b) scanf("%d%d",&a,&b) #define pri(a) printf("%d\n",a) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define MM 2000004 #define MN 1008 #define INF 2000000000 #define eps 1e-8 using namespace std; typedef long long ll; typedef unsigned long long ULL; ll c[MM],s[MM]; int f[MM],n; void update(int x,ll num) { for(int i=x;i<=n;i+=i&(-i)) c[i]+=num; } ll sum(int x) { ll ans=0; for(int i=x;i>=1;i-=i&(-i)) ans+=c[i]; return ans; } int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } void solve(int a,int b) { for(int i=find(a);i<=b;i=find(i+1)) { ll k=(ll)sqrt(s[i]); update(i,k-s[i]); s[i]=k; if(k==1) f[i]=i+1; } } int main() { int q,i,a,b,k; sca(n); for(i=0;i<=n+10;i++) f[i]=i; for(i=1;i<=n;i++) scanf("%lld",&s[i]),update(i,s[i]); sca(q); while(q--) { scanf("%d%d%d",&k,&a,&b); if(a>b) swap(a,b); if(!k) solve(a,b); else printf("%lld\n",sum(b)-sum(a-1)); } return 0; }
Wikioi 2492 树状数组+并查集(单点更新区间查询),布布扣,bubuko.com
Wikioi 2492 树状数组+并查集(单点更新区间查询)
原文地址:http://blog.csdn.net/u011466175/article/details/25393201