1129

来源:互联网 发布:json中包含html标签 编辑:程序博客网 时间:2024/05/16 10:12

题意:n个数,有q次询问,每次询问有两个操作 1.在区间【l, r】找到比v大的第一个数的下标 2.把【l,r】的数全部加上v。

思路: 裸线段树的题
写法1:线段树

#include <cstdio>#include <cstring>#include <iostream>#define mem(a) memset(a, 0, sizeof(a))using namespace std;const int inf = 0x3f3f3f3f;const int MAXN =100100;typedef long long LL;LL a[MAXN];LL lazy[MAXN<<2];struct T{    int l, r;    LL m;} tree[MAXN<<2];void pushdown(int k){    if(lazy[k])    {        tree[k<<1].m+=lazy[k];        tree[k<<1|1].m+=lazy[k];        lazy[k<<1]+=lazy[k];        lazy[k<<1|1]+=lazy[k];        lazy[k]=0;    }    return ;}void pushup(int k){    tree[k].m=max(tree[k<<1].m, tree[k<<1|1].m);}void build(int l, int r, int k){    tree[k].l=l;    tree[k].r=r;    tree[k].m=0;    if(l==r)    {        tree[k].m=a[l];        return;    }    int mid = (l+r)>>1;    build(l, mid, k<<1);    build(mid+1, r, k<<1|1);    pushup(k);}void update(int l, int r, int k, LL w){    if(tree[k].l>=l&&tree[k].r<=r)    {        tree[k].m+=w;        lazy[k]+=w;        return;    }    pushdown(k);    int mid = (tree[k].l+tree[k].r)>>1;//    if(l<=mid)//        update(l, r, k<<1, w);//    if(r>mid)//        update(l, r, k<<1|1, w);//两种写法都可以。    if(l>mid)        update(l, r, k<<1|1, w);    else if(r<=mid)        update(l,r,k<<1,w);    else    {        update(l, mid, k<<1, w);        update(mid+1, r, k<<1|1, w);    }    pushup(k);    return ;}int query(int l, int r, int k, LL c){    if(tree[k].m<c)        return -1;    if(tree[k].l==tree[k].r)        return tree[k].l;    pushdown(k);    pushup(k);    int mid = (tree[k].l+tree[k].r)>>1;    int x=-1, y=-1;    if(l<=mid)        x=query(l, r, k<<1, c);    if(x!=-1)return x;    if(r>mid)        y=query(l, r, k<<1|1, c);    return y;}int main(){    int t, q;    scanf("%d",&t);    while(t--)    {        int n;        memset(lazy, 0, sizeof(lazy));        scanf("%d %d",&n, &q);        for(int i=1; i<=n; ++i)            scanf("%lld", &a[i]);        build(1, n, 1);        int op, l, r;        LL v;        while(q--)        {            scanf("%d %d %d %lld", &op, &l,&r, &v);            if(op==1)                printf("%d\n", query(l, r, 1, v));            else                update(l, r, 1, v);        }    }    return 0;}

写法二:分块

#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;typedef long long LL;LL a[MAXN], b[MAXN];LL add[MAXN], mx[MAXN];int n, block;void init(){    block = sqrt(n);    int num = n/block;    for(int i=1; i<=num; ++i)        for(int j=(i-1)*block+1; j<=i*block; ++j)            mx[i]=max(a[j], mx[i]);//维护每一块的最大值    if(n%num) num++;//如果不湿刚好分完块        for(int i=num; i<=num; ++i)            for(int j=(num-1)*block+1; j<=n; ++j)                mx[i]=max(a[j],mx[i]);//对最后一块找最大//    for(int i=1;i<=num;++i)//        printf("%lld\n", mx[i]);    for(int i=1; i<=n; ++i)        b[i]=(i-1)/block+1;//标记下标i在第几块}void update(int l,int r,LL k){    int lq=b[l];    int rq=b[r];    //printf("%d %d\n", b[l], b[r]);    if(lq==rq)//如果在同一块, 暴力sqrt(n)更新    {        for(int i=l; i<=r; i++)        {            a[i]+=k;            if(a[i]+add[lq]>mx[lq])                mx[lq]=a[i]+add[lq];        }        return ;    }    for(int i=l; i<=lq*block; i++)    {        a[i]+=k;        if(a[i]+add[lq]>mx[lq])            mx[lq]=a[i]+add[lq];    }    for(int i=(rq-1)*block+1; i<=r; i++)    {        a[i]+=k;        if(a[i]+add[rq]>mx[rq])            mx[rq]=a[i]+add[rq];    }    //如果区间跨度大于两块,也就是r-l>1,直接更新块(分块的核心)    if(rq-lq>1)    {        for(int i=lq+1; i<rq; i++)        {            add[i]+=k;            mx[i]+=k;        }    }}LL query(int l,int r,LL k){    int lq=b[l];    int rq=b[r];    if(lq==rq)//只有一块    {        for(int i=l; i<=r; i++)        {            if(a[i]+add[lq]>=k) return i;        }        return -1;    }    //从左向右找,找到直接返回下标    for(int i=l; i<=lq*block; i++)    {        if(a[i]+add[lq]>=k) return i;    }    if(rq-lq>1)//有多块    {        for(int i=lq+1; i<rq; i++)        {            if(mx[i]>=k)            {                for(int j=(i-1)*block+1; j<=i*block; j++)                {                    if(a[j]+add[i]>=k) return j;                }            }        }    }    for(int i=(rq-1)*block+1; i<=r; i++)    {        if(a[i]+add[rq]>=k) return i;    }    return -1;}int main(){    int t;    scanf("%d", &t);    while(t--)    {        int q;        memset(add, 0, sizeof(add));        memset(mx, 0, sizeof(mx));        scanf("%d %d", &n, &q);        for(int i=1; i<=n; ++i)            scanf("%lld", &a[i]);        init();        while(q--)        {            int op, l,r;            LL k;            scanf("%d%d%d%lld",&op,&l,&r,&k);            if(op==1)                printf("%lld\n",query(l,r,k));            else            {                update(l,r,k);//                for(int i=1;i<=n;++i)//                    printf("%lld%c", a[i]+add[b[i]], " \n"[i==n]);            }        }    }    return 0;}
原创粉丝点击