您的位置:首页 > 产品设计 > UI/UE

HDU 4893 Wow! Such Sequence! (线段树单点更新+区间更新+区间查询+二分)

2016-07-09 10:04 274 查看

Wow! Such Sequence!

[align=center]Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4116    Accepted Submission(s): 1174

[/align]

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 F0 = 1,F1 = 1,Fibonacci number Fn is defined as Fn = Fn - 1 + Fn - 2 for n ≥ 2.

Nearest Fibonacci number of number x means the smallest Fn where |Fn - x| is also smallest.

Doge doesn't believe the machine could respond each request in less than 10ms. Help Doge figure out the reason.
 
[align=left]Input[/align]

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| < 231, all queries will be valid.
 
[align=left]Output[/align]

For each Type 2 ("query sum") operation, output one line containing an integer represent the answer of this query.
 
[align=left]Sample Input[/align]

1 1
2 1 1
5 4
1 1 7
1 3 17
3 2 4
2 1 5

 
[align=left]Sample Output[/align]

0
22

 
[align=left]Author[/align]

Fudan University

[align=left]Source[/align]
2014 Multi-University Training
Contest 3

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893

题目大意:给一个数列,三种操作,1是将k位置增加d,2是查询区间l到r中的数字和,3是将l到r中的数字都变成离它最近的斐波那契数

题目分析:操作1是单点更新,2是区间查询,3是区间更新,1和2都是裸的,3的话考虑到变化以后只对查询的结果有影响,因此可以加一个数组在单点更新的时候记录和fib的差值,fib预处理然后二分找一下,然后pushup得到区间差值和,这样区间更新直接加就好了,因为若两个3操作间没有1操作,这样数列其实是没有变化的,故更新过一次要将区间差值和置0

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
int const MAX = 1e5 + 5;
ll sum[MAX << 2], extra[MAX << 2];
ll fib[95];
bool lazy[MAX << 2];
int n, m;

void Fib()
{
fib[0] = 1;
fib[1] = 1;
for(int i = 2; i < 90; i++)
fib[i] = fib[i - 1] + fib[i - 2];
}

ll Get_extra(ll x)
{
if(x <= 1)
return 1;
int p = lower_bound(fib, fib + 90, x) - fib;
return (x - fib[p - 1] <= fib[p] - x) ? fib[p - 1] : fib[p];
}

void PushUp(int rt)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
extra[rt] = extra[rt << 1] + extra[rt << 1 | 1];
}

void PushDwon(int rt)
{
if(lazy[rt])
{
sum[rt << 1] += extra[rt << 1];
sum[rt << 1 | 1] += extra[rt << 1 | 1];
extra[rt << 1] = 0;
extra[rt << 1 | 1] = 0;
lazy[rt << 1] = true;
lazy[rt << 1 | 1] = true;
lazy[rt] = false;
}
}

void Build(int l, int r, int rt)
{
lazy[rt] = false;
sum[rt] = 0;
if(l == r)
{
extra[rt] = 1;
return;
}
int mid = (l + r) >> 1;
Build(lson);
Build(rson);
PushUp(rt);
}

void Update1(int k, ll d, int l, int r, int rt)
{
if(l == r)
{
sum[rt] += (ll)d;
extra[rt] = Get_extra(sum[rt]) - sum[rt];
return;
}
int mid = (l + r) >> 1;
PushDwon(rt);
if(k <= mid)
Update1(k, d, lson);
else
Update1(k, d, rson);
PushUp(rt);
}

void Update2(int L, int R, int l, int r, int rt)
{
if(L <= l && r <= R)
{
sum[rt] += extra[rt];
extra[rt] = 0;
lazy[rt] = true;
return;
}
int mid = (l + r) >> 1;
PushDwon(rt);
if(L <= mid)
Update2(L, R, lson);
if(mid < R)
Update2(L, R, rson);
PushUp(rt);
return;
}

ll Query(int L, int R, int l, int r, int rt)
{
if(L <= l && r <= R)
return sum[rt];
int mid = (l + r) >> 1;
PushDwon(rt);
ll ans = 0;
if(L <= mid)
ans += Query(L, R, lson);
if(mid < R)
ans += Query(L, R, rson);
return ans;
}

int main()
{
Fib();
while(scanf("%d %d", &n, &m) != EOF)
{
int tp;
Build(1, n, 1);
while(m --)
{
scanf("%d", &tp);
if(tp == 1)
{
int k;
ll d;
scanf("%d %I64d", &k, &d);
Update1(k, d, 1, n, 1);
}
else if(tp == 2)
{
int x, y;
scanf("%d %d", &x, &y);
printf("%I64d\n", Query(x, y, 1, n, 1));
}
else
{
int x, y;
scanf("%d %d", &x, &y);
Update2(x, y, 1, n, 1);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: