“华为杯”山东理工大学第十一届ACM程序设计竞赛 H 3∑+1? (线段树)
blem Description
玄黄最近发明了一个神奇的函数:
Xh(x)=3*( ∑(x的每一位) )+1 ,x为自然数。
现在你面前有n个自然数,玄黄现在要求你完成两种操作 。
1、帮玄黄求出这n个数中,区间 [l, r] 的和,并把答案告诉玄黄 。
2、帮玄黄把区间 [l, r] 中的每一个数 x 都变成 Xh(x)。Input
第一行输入一个正整数n(0 第二行输入n个自然数,下标从 1 至 n,每个自然数大小不超过 100000000003。
第三行输入一个正整数m(0 之后有m行,每行输入三个数op, l, r( 0 < op <3, 1 <= l <=r <=n ),op 代表玄黄要求你的操作编号,op 为 1 时执行第一种操作,op 为 2 时执行第二种操作,l 和 r 代表区间范围 。Output
当 op 为 1 时,输出区间 [l, r] 的和,每次输出占一行。
这是一个神奇的函数,,经过几次变换最后总能变成13...标记一下次数..赛后就a了.....
#include<bits/stdc++.h> using namespace std; #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define ls now<<1 #define rs now<<1|1 #define lson l,mid,ls #define rson mid+1,r,rs #define inf 0x3f3f3f3f #define int long long const int maxn=1e5+10; int tree[maxn*4],lazy[maxn*4]; void built(int l,int r,int now) { int mid=(l+r)>>1; if(l==r) { scanf("%lld",&tree[now]); return ; } built(lson); built(rson); tree[now]=tree[ls]+tree[rs]; } void updata(int l,int r,int now,int left,int right) { int mid=(l+r)>>1; if(lazy[now]>=50) return ; if(left<=l&&r<=right&&l==r) { int t=tree[now]; int s=1; while(t) { s+=(t%10)*3; t/=10; } tree[now]=s; lazy[now]++; return ; } if(mid>=left) updata(lson,left,right); if(mid<right) updata(rson,left,right); tree[now]=tree[ls]+tree[rs]; lazy[now]=min(lazy[ls],lazy[rs]); } int query(int l,int r,int now,int left,int right) { int mid=(l+r)>>1; if(left<=l&&r<=right) { return tree[now]; } int ans=0; if(mid>=left) ans+=query(lson,left,right); if(mid<right) ans+=query(rson,left,right); tree[now]=tree[ls]+tree[rs]; return ans; } #undef int int main() { #define int long long int n; scanf("%lld",&n); built(1,n,1); int m; scanf("%lld",&m); while(m--) { int cmd,l,r; scanf("%lld%lld%lld",&cmd,&l,&r); if(cmd==1) printf("%lld\n",query(1,n,1,l,r)); if(cmd==2) updata(1,n,1,l,r); } return 0; }