您的位置:首页 > 其它

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

2017-06-06 16:28 323 查看
DESCRIPTION

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

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

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

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

INPUT

输入第一行包含一个正整数t(1≤t≤100)t(1≤t≤100)
,表示有t组数据对于每组数据:第一行包含两个整数n(1≤n≤100000)n(1≤n≤100000),q(1≤q≤100000)q(1≤q≤100000),表示数的个数,以及询问的个数。第二行包含nn个整数
ai(1≤ai≤1000000000)ai(1≤ai≤1000000000)接下来q行,每行四个整数opt(1≤opt≤2),l,r(1≤l≤r≤n),v(1≤v≤1000000000)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

-11

这是一道线段树区间更新并维护最大值的线段树模板题,建树,更新只要照模板敲好,在每次询问的时候优先搜索左区间,注意搜索左边的时候,当前左子树的根保存的最大值并不一定在我们要查的【left,right】的区间就行了,代码里有注释。这里就不累赘了

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define siz 100005
#define LL long long
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
using namespace std;
struct node{
LL mx,addmark;
};
LL arr[siz];
node S[siz<<2];
int n,q;
LL max(LL a,LL b){
if(a>b) return a;
else return b;
}
void build(int root,int left,int right){
if(left==right){
S[root].mx=arr[left];
S[root].addmark=0;
return ;
}
int mid=(left+right)>>1;
build(lson(root),left,mid);
build(rson(root),mid+1,right);
S[root].mx=max(S[lson(root)].mx,S[rson(root)].mx);
S[root].addmark=0;
}
void pushdown(int root){
if(S[root].addmark!=0){
S[lson(root)].addmark+=S[root].addmark;
S[rson(root)].addmark+=S[root].addmark;
S[lson(root)].mx+=S[root].addmark;
S[rson(root)].mx+=S[root].addmark;
S[root].addmark=0;
}
}
void updata(int root,int left,int right,int l,int r,int v){
if(left==l&&r==right){
S[root].addmark+=v;
S[root].mx+=v;
return ;
}
pushdown(root);
int mid=(left+right)>>1;
if(r<=mid) updata(lson(root),left,mid,l,r,v);
else if(l>mid){
updata(rson(root),mid+1,right,l,r,v);
}
else{
updata(lson(root),left,mid,l,mid,v);
updata(rson(root),mid+1,right,mid+1,r,v);
}
S[root].mx=max(S[lson(root)].mx,S[rson(root)].mx);
}
int flag=0,ans;
void query(int root,int left,int right,int l,int r,int v){
if(flag) return ;
if(S[root].mx<v){
flag=1;
ans=-1;
return ;
}
if(left==right){
if(S[root].mx>=v){
flag=1;
ans=left;
return ;
}
else{
flag=1;
ans=-1;
return ;
}
}
pushdown(root);
int mid=(left+right)>>1;
if(r<=mid){
query(lson(root),left,mid,l,r,v);
}
else if(l>mid){
query(rson(root),mid+1,right,l,r,v);
}
else{
//if(left==l&&S[lson(root)].mx>=v){///不能这样去递归,因为lson(root)的区间是大于等于[left,right]的,
///这就意味着S[losn(root)].mx不一定在[left,right]里面
query(lson(root),left,mid,l,mid,v);///优先询问左子树
if(ans!=-1) return ;///如果左子树找到了大于等于v的,它一定是最左的
else{///否则,标记清零,再去寻找右子树。
flag=0;
}
query(rson(root),mid+1,right,mid+1,r,v);
}
}
///以下询问是别人的代码,可供参考
int query1(int root,int left,int right,int l,int r,int v){
if(S[root].mx<v) return -1;
if(l<=left&&r>=right){
if(left==right) return left;
int mid=(left+right)>>1;
pushdown(root);
if(S[lson(root)].mx>=v){
return query1(lson(root),left,mid,l,r,v);
}
else{
return query1(rson(root),mid+1,right,l,r,v);
}
}
else{
pushdown(root);
int mid=(left+right)>>1;
int res;
if(l<=mid){
res=query1(lson(root),left,mid,l,r,v);
if(res<=r&&res!=-1)
return res;
}
if(r>mid){
res=query1(rson(root),mid+1,right,l,r,v);
if(res<=r&&res!=-1) return res;
}
}
return -1;
}
void solve(){
build(1,1,n);
int opt,l,r,v;
while(q--){
flag=0,ans=-1;
scanf("%d %d %d %d",&opt,&l,&r,&v);
if(opt==1){
query(1,1,n,l,r,v);
printf("%d\n",ans);
// printf("%d\n",query1(1,1,n,l,r,v));
}else{
updata(1,1,n,l,r,v);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%lld",&arr[i]);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: