您的位置:首页 > 其它

玲珑OJ 1129 - 喵哈哈村的战斗魔法师丶坏坏い月

2017-05-30 22:29 281 查看
1129 - 喵哈哈村的战斗魔法师丶坏坏い月

Time Limit:3s Memory Limit:256MByte

Submissions:315Solved:71

DESCRIPTION

坏坏い月是月大叔的ID,他是一个掌握者772002种魔法的物理系战士,最擅长的技能就是搞事。今天他又要开始搞事了。

给你n

个数,你需要实现一下操作:

l r v ,在[l,r]区间内找到第一个大于等于v的数,输出这个数的下标,如果找不到的话,请输出-1噢

l r v,让[l,r]区间所有数增加v

INPUT

输入第一行包含一个正整数t(1≤t≤100)

,表示有t组数据 对于每组数据: 第一行包含两个整数n(1≤n≤100000),q(1≤q≤100000),表示数的个数,以及询问的个数。 第二行包含n个整数 ai(1≤ai≤1000000000) 接下来q行,每行四个整数opt(1≤opt≤2),l,r(1≤l≤r≤n),v(1≤v≤1000000000)

OUTPUT

对于每个询问,输出一行表示答案.

SAMPLE INPUT

1 5 3 1 2 3 4 5 1 1 2 3 2 1 2 3 1 1 2 3

SAMPLE OUTPUT

-1 1

博客本来准备不更新了,今天看到这个题目 - -,想起如果用树维护又是树套树啥的,麻烦死了,结果看到题解->分块!
看了分块思想之后,感觉好巧妙啊,时间复杂度 O(m*sqrt(n)),这么难的数据结构题寥寥数十行就解决了,遂决定补题解!

官方题解:
H 喵哈哈村的战斗魔法师丶坏坏い月
常见的数据结构中,我们选择使用分块来处理这道题。
我们将n个数,分成sqrt(n)块,每块里面的元素最多有sqrt(n)个元素。对于每一个块,我们维护Upd[i]表示这个块整个增加了多少,Max[i]表示这个块内的最大值是多少。
对于查询和更新,如果完全囊括了块的话,我们就只对Upd[i]和Max[i]进行更新,否则的话,我们就暴力更新这个块的元素即可。
总体复杂度O(n*根号n)

Upd相当于一个标记,只起到记录的作用,两端暴力更新~

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 100000;
int n,m;
LL a
,Max
,Upd
;
int pos
;
int block = 0;
void reset(int x)
{
int l=(x-1)*block+1,r=min(x*block,n);
for(int i=l; i<=r; i++)
Max[x]=max(Max[x],a[i]);
}

void update(int x,int y,LL v)
{
if(pos[x]==pos[y])
{
for(int i=x; i<=y; i++)a[i]=a[i]+v;
}
else
{
for(int i=x; i<=pos[x]*block; i++)a[i]=a[i]+v;
for(int i=(pos[y]-1)*block+1; i<=y; i++)a[i]=a[i]+v;
}
reset(pos[x]);
reset(pos[y]);
for(int i=pos[x]+1; i<pos[y]; i++)
Upd[i]+=v;
}

int findidx(int x,LL v)
{
int l=(x-1)*block+1,r=min(x*block,n);
for(int i=l; i<=r; i++)
{
if(a[i]+Upd[x]>=v) return i;
}
}
int query(int x,int y,LL v)
{
if(pos[x]==pos[y])
{
for(int i=x; i<=y; i++)if(a[i]+Upd[pos[i]]>=v) return i;
}
else
{
///暴力找左边
for(int i=x; i<=pos[x]*block; i++)
if(a[i]+Upd[pos[i]]>=v) return i;
///分块找中间
for(int i=pos[x]+1; i<pos[y]; i++)
if(Max[i]+Upd[i]>=v)
{
return findidx(i,v);
}
///暴力找右边
for(int i=(pos[y]-1)*block+1; i<=y; i++)
if(a[i]+Upd[pos[i]]>=v) return i;
}

return -1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(Max,0,sizeof(Max));
memset(Upd,0,sizeof(Upd));
scanf("%d%d",&n,&m);
block = int(sqrt(n));
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
pos[i]=(i-1)/block+1; ///记录每个元素属于哪个块
}
int k; ///块的个数
if(n%block)k=n/block+1;
else k=n/block;
for(int i=1; i<=k; i++)
{
reset(i);
}
while(m--)
{
int opt,l,r;
LL v;
scanf("%d%d%d%lld",&opt,&l,&r,&v);
if(opt==1)
{
printf("%d\n",query(l,r,v));
}
else
{
update(l,r,v);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: