整体二分大概就是这么一种算法
- 基本上和树状数组一起用
- 离线
- 二分
好进入正文
先给个题呗
这题给出多个询问 而你每次询问的复杂度是 \(O(n \log n)\) 看似很优秀了?
但你这样的话 所有的复杂度都是 \(O(n \log n)\) 整体复杂度乘个 \(Q\) 接受不了…
二分怎么写?
while(l <= r) {
int mid = l + r >> 1 ;
if(chk(mid)) { ans = mid ; l = mid + 1 ; }
else r = mid - 1 ;
}
大概是这样 反过来的不说了…
然后每次边做 边丢队列里…
存俩队列 q1 , q2
满足 条件的放 q2 减掉左区间的贡献
不满足的放 q1 不做修改
易证明 q1.size + q2.size = q.size
然后抵消贡献 这个贡献有时候可以用-1 +1 来处理掉(即存两个)
所以归位 然后接着分治 如果说 L==R 了 就和二分一个样子 赋上 ans = L 跑路
// Isaunoya
#include
using namespace std ;
using LL = long long ;
using uint = unsigned int ;
#define int long long
#define fir first
#define sec second
#define pb push_back
#define mp(x , y) make_pair(x , y)
template < typename T > inline void read(T & x) { x = 0 ; int f = 1 ; register char c = getchar() ;
for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
x *= f ;
}
template < typename T > inline void print(T x) {
if(! x) { putchar('0') ; return ; } static int st[105] ;
if(x < 0) putchar('-') , x = -x ; int tp = 0 ;
while(x) st[++ tp] = x % 10 , x /= 10 ; while(tp) putchar(st[tp --] + '0') ;
}
template < typename T > inline void print(T x , char c) { print(x) ; putchar(c) ; }
template < typename T , typename ...Args > inline void read(T & x , Args & ...args) { read(x) ; read(args...) ; }
template < typename T > inline void sort( vector < T > & v) { sort(v.begin() , v.end()) ; return ; }
template < typename T > inline void unique( vector < T > & v) { sort(v) ; v.erase(unique(v.begin() , v.end()) , v.end()) ; }
template < typename T > inline void cmax(T & x , T y) { if(x < y) x = y ; return ; }
template < typename T > inline void cmin(T & x , T y) { if(x > y) x = y ; return ; }
int n , m , k ;
const int N = 3e5 + 10 ;
struct node { int v , nxt ; } e[N] ;
struct Node { int ned , id , hd ; } q[N] , _q[N << 1] ;
int head[N] , cnt = 0 ;
int L[N] , R[N] , val[N] ;
inline void addedge(int u , int v) { e[++ cnt].v = v ; e[cnt].nxt = q[u].hd ; q[u].hd = cnt ; }
int c[N << 1] ;
inline int low(int x) { return x & -x ; }
inline void add(int x , int y) { for( ; x <= N << 1 ; x +=low(x)) c[x] += y ; }
inline int query(int x) { int ans = 0 ; for( ; x ; x ^= low(x)) ans += c[x] ; return ans ; }
int ans[N] ;
inline void solve(int l , int r , int x , int y) {
if(l == r) { for(register int i = x ; i <= y ; i ++) ans[q[i].id] = l ; return ; }
int mid = l + r >> 1 ; int ql = 0 , qr = n ;
for(register int i = l ; i <= mid ; i ++) add(L[i] , val[i]) , add(R[i] + 1 , - val[i]) ;
for(register int i = x ; i <= y ; i ++) {
int tmp = 0 ;
for(register int j = q[i].hd ; j && tmp <= q[i].ned ; j = e[j].nxt) {
int v = e[j].v ;
tmp += query(v + m) + query(v) ;
}
if(tmp >= q[i].ned) _q[++ ql] = q[i] ;
else { _q[++ qr] = q[i] ; _q[qr].ned -= tmp ; }
}
for(register int i = l ; i <= mid ; i ++) add(L[i] , - val[i]) , add(R[i] + 1 , val[i]) ;
for(register int i = 1 ; i <= ql ; i ++) q[x + i - 1] = _q[i] ;
for(register int i = n + 1 ; i <= qr ; i ++) q[x + ql + i - n - 1] = _q[i] ;
solve(l , mid , x , x + ql - 1) ;
solve(mid + 1 , r , y - qr + n + 1 , y) ;
}
signed main() {
read(n , m) ; for(register int i = 1 ; i <= m ; i ++) { int x ; read(x) ; addedge(x , i) ; }
for(register int i = 1 ; i <= n ; i ++) read(q[i].ned) , q[i].id = i ;
read(k) ; for(register int i = 1 ; i <= k ; i ++) read(L[i] , R[i] , val[i]) ;
for(register int i = 1 ; i <= k ; i ++) if(L[i] > R[i]) R[i] += m ; solve(1 , k + 1 , 1 , n) ;
for(register int i = 1 ; i <= n ; i ++)
if(ans[i] == k + 1) puts("NIE") ;
else printf("%lld\n" , ans[i]) ;
return 0 ;
}