題目
題解
先求一個前綴和
首先由抽屜原理可以得:
如果R-L+1>=P,則可以直接輸出0
因爲一定有兩個前綴和在P的模意義下是相等的
然後把(sum[l] - sum[l-1]) % P 到 (sum[r] - sum[l-1]) % P依次放進平衡樹中,在插入前求它的前驅,兩者相減後,即使對於當前點爲右端點所得到的最小子串和
這樣也不會再去取模了
感覺自己的數據結構的題做得太少,可能還需要一定的積累,記得解題的方法很重要
代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 1e6 +3;
int ch[MAXN][2] , val[MAXN] , cnt[MAXN] , siz[MAXN] , fa[MAXN];
int root , ncnt;
int chk( int x ){
return ch[fa[x]][1] == x;
}
void pushup( int x ){
siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x];
}
void rorate( int x ){
int f = fa[x] , ff = fa[f] , w = chk( x );
ch[f][w] = ch[x][w^1];
fa[ch[x][w^1]] = f;
ch[ff][chk(f)] = x;
fa[x] = ff;
ch[x][w^1] = f;
fa[f] = x;
pushup( f );pushup( x );
}
void splay( int x , int goal ){
while( fa[x] != goal ){
int f = fa[x] , ff = fa[f];
if( ff != goal ){
if( chk( x) == chk(f ) ) rorate( f );
else
rorate( x );
}
rorate( x );
}
if( !goal ) root = x;
}
void find_( int x ){
if( !root ) return ;
int cur = root;
while( ch[cur][val[cur] < x] && val[cur] != x ){
cur = ch[cur][val[cur] < x];
}
splay( cur , 0 );
}
void insert_( int x ){
int cur = root , p = 0;
while( cur && val[cur] != x ){
p = cur;
cur = ch[cur][val[cur] < x];
}
if( cur ){
cnt[cur] ++;
}
else{
cur = ++ncnt;
if( p ) ch[p][x>val[p]] = cur;
ch[cur][0] = ch[cur][1] = 0;
val[cur] = x;cnt[cur] = 1;
siz[cur] = 1;fa[cur] = p;
}
splay( cur , 0 );
}
int kth( int k ){
int cur = root;
while( true ){
if( siz[ch[cur][0]] >= k && ch[cur][0] ){
cur = ch[cur][0];
}
else if( siz[ch[cur][0]] + cnt[cur] < k ){
k -= siz[ch[cur][0]] + cnt[cur];
cur = ch[cur][1];
}
else
return cur;
}
}
int pre( int x ){
find_( x );
if( val[root] <= x ) return root;
int cur = ch[root][0];
while( ch[cur][1] ){
cur = ch[cur][1];
}
return cur;
}
int n , Q , A[MAXN] , sum[MAXN];
void read( int &x ){
x = 0;char s = getchar();
while( s < '0' || s > '9' ) s = getchar();
while( s >= '0' && s <= '9' ){
x = x * 10 + s -'0';
s = getchar();
}
}
int main()
{
freopen( "array.in" , "r" , stdin );
freopen( "array.out" , "w" , stdout );
read( n );read(Q);
for( int i = 1 ; i <= n ; i ++ ){
read( A[i] );
sum[i] = sum[i-1] + A[i];
}
while( Q -- ){
int L , R , P;
read( L );read( R );read( P );
if( R - L + 1 >= P ){
printf( "0\n" );
continue;
}
for( int i = 0 ; i <= P ; i ++ ){
fa[i] = val[i] = ch[i][0] = ch[i][1] = siz[i] = cnt[i] = 0;
}
root = 0;ncnt = 0;
int ans = A[L] % P;
for( int i = L ; i <= R ; i ++ ){
int tot = ( sum[i] - sum[L-1] ) % P;
if( i == L )
insert_( tot );
else{
int j = pre( tot );
ans = min( ans , tot - val[j] );
insert_( tot );
}
}
printf( "%d\n" , ans );
}
return 0;
}