玲瓏OJ 1129 - 喵哈哈村的戰鬥魔法師丶壞壞い月

1129 - 喵哈哈村的戰鬥魔法師丶壞壞い月

Time Limit:3s Memory Limit:256MBytehtml

Submissions:315Solved:71ios

DESCRIPTION

壞壞い月是月大叔的ID,他是一個掌握者772002種魔法的物理系戰士,最擅長的技能就是搞事。今天他又要開始搞事了。數據結構

給你natom

個數,你須要實現一下操做:spa

  1. l r v ,在[l,r]區間內找到第一個大於等於v的數,輸出這個數的下標,若是找不到的話,請輸出-1噢code

  2. l r v,讓[l,r]區間全部數增長vxml

INPUT
輸入第一行包含一個正整數 t(1t100)

,表示有t組數據 對於每組數據: 第一行包含兩個整數n(1n100000),q(1q100000),表示數的個數,以及詢問的個數。 第二行包含n個整數 ai(1ai1000000000) 接下來q行,每行四個整數opt(1opt2),l,r(1lrn),v(1v1000000000)htm

 
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[N],Max[N],Upd[N];
int pos[N];
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;
}
相關文章
相關標籤/搜索