1. 程式人生 > >玲瓏OJ 1129 - 喵哈哈村的戰鬥魔法師丶壞壞い月

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

min return itl ati data- mar names 題解 記錄

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

Time Limit:3s Memory Limit:256MByte

Submissions:315Solved:71

DESCRIPTION

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

給你n

個數,你需要實現一下操作:

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

  2. l r v,讓[l,r]區間所有數增加v

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

,表示有t組數據 對於每組數據: 第一行包含兩個整數

n(1n100000),q(1q100000),表示數的個數,以及詢問的個數。 第二行包含n個整數 ai(1ai1000000000) 接下來q行,每行四個整數opt(1opt2),l,r(1lrn),v(1v1000000000)

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; }

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