题目
点这里看题目。
分析
放在 T3 但明明还没有 T1 难。
由于整个问题只有查询,并且各个岛屿都是独立的,所以显然可以拆成前缀进行询问。
前缀的话就比较自由了。考虑已有的一个岛屿集,我们分析一下询问在干什么:
-
如果某个岛屿 ((a,b)) 满足 (b>d) ,那么对于所有这样的岛屿, (b) 都已经没用了。我们相当于是求有多少个 (a) 满足 (aoplus cle d) ,这是常规的 0-1Trie 可以解决的问题。
-
如果某个岛屿 ((a,b)) 满足 (ble d) ,那么对于所有这样的岛屿, (d) 都已经没用了。我们相当于是求有多少个 (a) 使得 (aoplus cle b) 得到了满足。那么考虑一对 ((a,b)) 会给哪些 (c) 带来贡献。在二进制的第 (k) 位上:
- 如果 (b) 为 1 ,此时 (aoplus c) 如果为 0 , (c) 在 (0sim k-1) 位的值就随意了,因此这一部分的 (c) 都可以获得 1 的贡献;如果 (aoplus c) 为 1 ,那么 (c) 就需要进入更低位判断。
- 如果 (b) 为 0 ,此时 (aoplus c) 只能为 0 ,这一位就确定了。
如果同样用 0-1Trie 进行维护,那么可以在情况 1 中,在 (aoplus c) 为 0 的一侧打上标记(可以直接标记永久化)。查询的时候直接顺着 (c) 一路向下查询即可。
再思考一下外层的结构,如果用树套树会获得 MLE 的好成绩,外层使用 CDQ 分治即可省下来这部分空间。
不妨设 (V) 为值域,时间为 (O(nlog_2nlog_2|V|)) ,空间为 (O(nlog_2|V|)) 。
代码
#include <cstdio>
#include <algorithm>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
const int BIT = 23, LIM = ( 1 << 24 ) - 1;
const int MAXN = 1e5 + 5, MAXS = MAXN * 25;
template<typename _T>
void read( _T &x )
{
x = 0; char s = getchar(); int f = 1;
while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ) putchar( '-' ), x = - x;
if( 9 < x ) write( x / 10 );
putchar( x % 10 + '0' );
}
template<typename _T>
_T MIN( const _T a, const _T b )
{
return a < b ? a : b;
}
struct Event
{
int i, b, c, id;
Event() { i = b = c = id = 0; }
Event( int I, int B, int C, int ID ) { i = I, b = B, c = C, id = ID; }
bool operator < ( const Event &g ) const { return i == g.i ? id < g.id : i < g.i; }
}eve[MAXN * 3];
int seq[MAXN * 3], tmp[MAXN * 3], len;
int res[MAXN * 3];
int A[MAXN], B[MAXN];
int N, Q;
namespace Trie
{
int ch[2][MAXS], su[MAXS];
int rt, tot;
void Clear() { rt = tot = 0; }
inline int NewNode()
{
int r = ++ tot;
ch[0][r] = ch[1][r] = su[r] = 0;
return r;
}
void Insert( int &x, const int k, const int v )
{
su[x = x ? x : NewNode()] ++;
if( k < 0 ) return ;
Insert( ch[v >> k & 1][x], k - 1, v );
}
int Query( const int &x, const int k, const int XOR, const int lim )
{
if( ! x ) return 0;
if( k < 0 ) return su[x];
int dif = XOR >> k & 1;
if( ! ( lim >> k & 1 ) ) return Query( ch[dif][x], k - 1, XOR, lim );
return Query( ch[dif ^ 1][x], k - 1, XOR, lim ) + su[ch[dif][x]];
}
void Insert( const int v ) { Insert( rt, BIT, v ); }
int Query( const int XOR, const int lim ) { return Query( rt, BIT, XOR, lim ); }
}
namespace NewbieTrie
{
int ch[2][MAXS << 1], tag[MAXS << 1];
int rt, tot;
void Clear() { rt = tot = 0; }
inline int NewNode()
{
int r = ++ tot;
ch[0][r] = ch[1][r] = tag[r] = 0;
return r;
}
void Add( int &x, const int v ) { tag[x = x ? x : NewNode()] += v; }
void Insert( int &x, const int k, const int a, const int b )
{
x = x ? x : NewNode();
if( k < 0 ) return void( tag[x] ++ );
int p = a >> k & 1, q = b >> k & 1;
if( q == 1 )
{
Add( ch[p][x], 1 );
Insert( ch[1 ^ p][x], k - 1, a, b );
}
else Insert( ch[p][x], k - 1, a, b );
}
int Query( const int &x, const int k, const int v )
{
if( ! x ) return 0; int ret = tag[x];
if( ~ k ) ret += Query( ch[v >> k & 1][x], k - 1, v );
return ret;
}
int Query( const int v ) { return Query( rt, BIT, v ); }
void Insert( const int a, const int b ) { Insert( rt, BIT, a, b ); }
}
void CDQ( const int l, const int r )
{
if( l >= r ) return ;
int mid = l + r >> 1;
CDQ( l, mid ), CDQ( mid + 1, r );
// now seq[l:mid] and seq[mid+1:r] is already sorted by b
int i = l, j = mid + 1, u, v, k = l - 1;
NewbieTrie :: Clear();
for( ; i <= mid || j <= r ; )
{
u = seq[i], v = seq[j];
if( i <= mid && ( j > r || eve[u].b <= eve[v].b ) )
{
if( eve[u].id < 0 )
NewbieTrie :: Insert( eve[u].c, eve[u].b );
tmp[++ k] = seq[i ++];
}
else
{
if( eve[v].id > 0 )
res[eve[v].id] += NewbieTrie :: Query( eve[v].c );
tmp[++ k] = seq[j ++];
}
}
// Process to those b <= d
i = mid, j = r, Trie :: Clear();
for( ; i >= l || j > mid ; )
{
u = seq[i], v = seq[j];
if( i >= l && ( j <= mid || eve[u].b > eve[v].b ) )
{
if( eve[u].id < 0 )
Trie :: Insert( eve[u].c );
i --;
}
else
{
if( eve[v].id > 0 )
res[eve[v].id] += Trie :: Query( eve[v].c, eve[v].b );
j --;
}
}
// Process to those b > d
rep( i, l, r ) seq[i] = tmp[i];
// Merge!!
}
int main()
{
read( N ), read( Q );
rep( i, 1, N )
{
read( A[i] ), read( B[i] );
eve[++ len] = Event( i, B[i], A[i], - i );
}
rep( i, 1, Q )
{
int l, r, c, d;
read( l ), read( r ), read( c ), read( d );
eve[++ len] = Event( l - 1, d, c, i << 1 );
eve[++ len] = Event( r, d, c, i << 1 | 1 );
}
rep( i, 1, len ) seq[i] = i;
std :: sort( eve + 1, eve + 1 + len );
CDQ( 1, len );
rep( i, 1, Q )
write( res[i << 1 | 1] - res[i << 1] ), putchar( '
' );
return 0;
}