http://acm.hdu.edu.cn/showproblem.php?pid=4893
Wow! Such Sequence!
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3341 Accepted Submission(s): 966
Problem Description
Recently, Doge got a funny birthday present from his new friend, Protein Tiger from St. Beeze College. No, not cactuses. It's a mysterious blackbox.
After some research, Doge found that the box is maintaining a sequence an of n numbers internally, initially all numbers are zero, and there are THREE "operations":
1.Add d to the k-th number of the sequence.
2.Query the sum of ai where l ≤ i ≤ r.
3.Change ai to the nearest Fibonacci number, where l ≤ i ≤ r.
4.Play sound "Chee-rio!", a bit useless.
Let F 0 = 1,F 1 = 1,Fibonacci number Fn is defined as F n = F n - 1 + F n - 2 for n ≥ 2.
Nearest Fibonacci number of number x means the smallest Fn where |F n - x| is also smallest.
Doge doesn't believe the machine could respond each request in less than 10ms. Help Doge figure out the reason.
After some research, Doge found that the box is maintaining a sequence an of n numbers internally, initially all numbers are zero, and there are THREE "operations":
1.Add d to the k-th number of the sequence.
2.Query the sum of ai where l ≤ i ≤ r.
3.Change ai to the nearest Fibonacci number, where l ≤ i ≤ r.
4.Play sound "Chee-rio!", a bit useless.
Let F 0 = 1,F 1 = 1,Fibonacci number Fn is defined as F n = F n - 1 + F n - 2 for n ≥ 2.
Nearest Fibonacci number of number x means the smallest Fn where |F n - x| is also smallest.
Doge doesn't believe the machine could respond each request in less than 10ms. Help Doge figure out the reason.
Input
Input contains several test cases, please process till EOF.
For each test case, there will be one line containing two integers n, m.
Next m lines, each line indicates a query:
1 k d - "add"
2 l r - "query sum"
3 l r - "change to nearest Fibonacci"
1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, |d| < 2 31, all queries will be valid.
For each test case, there will be one line containing two integers n, m.
Next m lines, each line indicates a query:
1 k d - "add"
2 l r - "query sum"
3 l r - "change to nearest Fibonacci"
1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, |d| < 2 31, all queries will be valid.
Output
For each Type 2 ("query sum") operation, output one line containing an integer represent the answer of this query.
Sample Input
1 1 2 1 1 5 4 1 1 7 1 3 17 3 2 4 2 1 5
Sample Output
0 22
Author
Fudan University
Source
开始理所应当的写起了树状数组, 写到一半才发现了修改成斐波那契是区间修改. 随便叫了一个T, 被说教. 然后两个月后..
也就是现在, 重新想了想这道题, 开始还是没有弄对. 以为只要给线段树上的点打上要修改成Fibonacci的标记就可以了, 修改的时候还是点修改.. 果然又T. 第二次写线段树, 错误很很典型:
名称问题. query(根,左,右,待修改区间左,待修改区间右) 因为还没形成习惯结果全给弄混了. 现在比较习惯的: query(int root,int l,int r,int L,int R)
区间的开闭, 以及求子节点范围. 如果半开半闭当然直接相加除以2就可以, 但是两边都闭的是不能那样写的. 需要mid=(l+r)>>1, [l,mid] [mid+1,r]. 比较下来还是半开半闭最科学.
区间判断相交问题. 不知为何, 写了两次都犯了同一个错误: 判断[l,r) 是否在[L,R)内, 却写成了 L<=l && r<=R . 为什么会习惯性地这样写呢..
HDU 的lld.... I64d. 我去.
因为第二次还是没能写对, 随意找了一个题解, 然后只看了这一句话:
处理的方案就是提前对每一段的 区间和 都找到相应的 Fibonacci 数作为映射
...明白了
也就是因为修改成Fibonacci是区间操作, 所以需要在树上事先维护好, 将它转换成log(n)的操作. 而将一个点增加一个值本来就是log(n)的点操作, 只要记得顺带维护好Fibonacci的值就好.
树上的点有三个值: v - 区间和. f - 区间如果被全部转换成了Fibonacci序列后的区间和. type - 是否整棵子树都是Fibonacci数(0不是, 1是).
#include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include <cassert> #include <algorithm> #include <string> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <numeric> #include <bitset> #include <cstdio> #include <cstring> using namespace std; #define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++) #define fer(i, x, n) for (int i = (int)(x), _n = (int)(n); i < _n; i++) #define rof(i, n, x) for (int i = (int)(n), _x = (int)(x); i-- > _x; ) #define fch(i, x) for (__typeof(x.begin()) i = x.begin(); i != x.end(); i++) #define sz(x) (int((x).size())) #define pb push_back #define mkp make_pair #define all(X) (X).begin(),(X).end() #define X first #define Y second template<class T> inline void smin(T &a, T b){if(b<a)a=b;} template<class T> inline void smax(T &a, T b){if(a<b)a=b;} typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll,ll> pll; typedef vector<pii> vii; typedef vector<int> vi; typedef vector<vi> vvi; typedef vector<vii> vvii; typedef vector<char> VC; typedef vector<string> VS; typedef vector<ll> VL; typedef vector<double> VD; typedef set<int> SI; typedef set<string> SS; typedef map<int, int> MII; typedef map<string, int> MSI; template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));} template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));} template<class T> inline void CLR(T &A){A.clear();} /** Constant List .. **/ //{ const int dx4[] = {-1, 0, 1, 0}; const int dy4[] = {0, 1, 0, -1}; const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1}; const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1}; const int mod = 1000000007; const int INF = 0x3f3f3f3f; //} template<class T> inline T min(T a, T b, T c){return min(min(a, b), c);} template<class T> inline T max(T a, T b, T c){return max(max(a, b), c);} template<class T> inline T min(T a, T b, T c, T d){return min(min(a, b), min(c, d));} template<class T> inline T max(T a, T b, T c, T d){return max(max(a, b), max(c, d));} template<class T> inline T sqr(T a){return a*a;} template<class T> inline T cub(T a){return a*a*a;} //// int n,m,i,j,k,tmp,type,x,y; const int N = 100009; struct node{ ll v,f; int type; // 0 混合; 1 全fib; }t[N*6]; const ll mx = 1LL<<60; ll fib[100000],num; void init_fib(){ fib[0]=fib[1]=1; int i=1; while(fib[i]<mx) fib[i+1]=fib[i-1]+fib[i],i++; num = i; } void init_tree(int root,int l,int r){ if(l+1==r) t[root].v=t[root].type=0,t[root].f=1; else{ int tl = root<<1, tr = root<<1|1, mid = (l+r)>>1; init_tree(tl,l,mid); init_tree(tr,mid,r); t[root].v=t[root].type=0, t[root].f = t[tl].f + t[tr].f; } } ll near(ll x){ if(x<=1) return 1; int tmp = upper_bound(fib,fib+num,x)-fib; return (abs(fib[tmp-1]-x)>abs(x-fib[tmp]))?fib[tmp]:fib[tmp-1]; } void add(int root, int l, int r ,int L, int R, int d){ if(r<=L || R<=l) return; if(L<=l && r<=R){ t[root].v += d; t[root].type = 0; t[root].f = near(t[root].v); return; }else{ int tl = root<<1, tr = root<<1|1, mid = (l+r)>>1; if(t[root].type == 1){ t[tl].type = t[tr].type = 1; t[tl].v = t[tl].f; t[tr].v = t[tr].f; t[root].type = 0; } add(tl,l,mid,L,R,d); add(tr,mid,r,L,R,d); t[root].type = 0; t[root].f = t[tl].f + t[tr].f; t[root].v = t[tl].v + t[tr].v; return; } } ll query(int root,int l,int r,int L,int R){ if(r<=L || R<=l) return 0; if(L<=l && r<=R){ return t[root].v; }else{ int tl = root<<1, tr = root<<1|1, mid = (l+r)>>1; if(t[root].type == 1){ t[tl].type = t[tr].type = 1; t[tl].v = t[tl].f; t[tr].v = t[tr].f; } ll ret = query(tl,l,mid,L,R) + query(tr,mid,r,L,R); return ret; } } void change(int root,int l,int r,int L,int R){ if(r<=L || R<=l || t[root].type==1) return; if(L<=l && r<=R){ t[root].type = 1; t[root].v = t[root].f; return; }else{ int tl = root<<1, tr = root<<1|1, mid = (l+r)>>1; change(tl,l,mid,L,R); change(tr,mid,r,L,R); t[root].v = t[tl].v + t[tr].v; if(t[tl].type == 1 && t[tr].type == 1) t[root].type = 1; } } int main() { //freopen("in.txt","r",stdin); ios_base::sync_with_stdio(0); init_fib(); while(~scanf("%d %d",&n,&m)){ int _n = 1; while(_n<n) _n<<=1; n=_n+1; init_tree(1,1,n); while(m--){ scanf("%d %d %d",&type,&x,&y); switch(type){ case 1: add(1,1,n,x,x+1,y); break; case 2: printf("%I64d\n",query(1,1,n,x,y+1) ); break; case 3: change(1,1,n,x,y+1); break; default: break; } } } return 0; }