zoukankan      html  css  js  c++  java
  • Solution -「多校联训」神

    (mathcal{Description})

      Link.

      给定 (n) 阶排列 (a)(q) 次询问,每次给出 (1le l_1le r_1<l_2le r_2le n)(r_1-l_1=r_2-l_2),询问满足 (forall jin[1,r_1-l_1+1],~a_{j+l_1-1}<a_{b_j+l_2-1})((r_1-l_1+1)) 阶排列 (b) 的个数,模 ((10^9+7))

      多测,(sum n,sum qle10^5)(a) 的逆序对数 (le10^5)

    (mathcal{Solution})

      暴力做法:设前后询问区间为 (A)(B),把两个区间的元素丢一起升序排序,则每个 (A) 中元素选择匹配点的方案数为其后方 (B) 类元素个数减去 (A) 类元素个数。

      将同属一类的连续元素视为一段,那么有结论:段数为 (mathcal O(sqrt n)) 级别。

    每个 (B) 段与后方所有 (A) 段组成逆序对,故段数与逆序对数是平方关系,而逆序对数是 (mathcal O(n)) 级别,故段数 (mathcal O(sqrt n)) 级别。

      利用主席数查找前驱快速求出每段长度,即可 (mathcal O(nlog n+qsqrt nlog n)) 求解。

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cstdio>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    const int MAXN = 1e5, MOD = 1e9 + 7;
    int n, q, root[MAXN + 5], fac[MAXN + 5], ifac[MAXN + 5];
    
    inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
    inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
    inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
    inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
    inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
    inline int mpow( int a, int b ) {
        int ret = 1;
        for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
        return ret;
    }
    
    inline void init() {
        fac[0] = 1;
        rep ( i, 1, MAXN ) fac[i] = mul( i, fac[i - 1] );
        ifac[MAXN] = mpow( fac[MAXN], MOD - 2 );
        per ( i, MAXN - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );
    }
    
    struct SegmentTree {
        static const int MAXND = 2e6;
        int node, ch[MAXND][2], sum[MAXND];
    
        inline void insert( int& u, const int l, const int r, const int x ) {
            int v = u, mid = l + r >> 1; u = ++node;
            ch[u][0] = ch[v][0], ch[u][1] = ch[v][1], sum[u] = sum[v] + 1;
            if ( l == r ) return ;
            if ( x <= mid ) insert( ch[u][0], l, mid, x );
            else insert( ch[u][1], mid + 1, r, x );
        }
    
        inline int count( const int u, const int v, const int l, const int r,
          const int ql, const int qr ) {
            if ( !v ) return 0;
            if ( ql <= l && r <= qr ) return sum[v] - sum[u];
            int mid = l + r >> 1, ret = 0;
            if ( ql <= mid ) ret += count( ch[u][0], ch[v][0], l, mid, ql, qr );
            if ( mid < qr ) ret += count( ch[u][1], ch[v][1], mid + 1, r, ql, qr );
            return ret;
        }
    
        inline int prefix( const int u, const int v, const int l, const int r,
          const int x ) {
            if ( !x || sum[v] <= sum[u] ) return 0;
            if ( l == r ) return l;
            int mid = l + r >> 1;
            if ( x <= mid ) return prefix( ch[u][0], ch[v][0], l, mid, x );
            if ( int t = prefix( ch[u][1], ch[v][1], mid + 1, r, x ); t ) return t;
            return prefix( ch[u][0], ch[v][0], l, mid, x );
        }
    } sgt;
    
    int main() {
        freopen( "god.in", "r", stdin );
        freopen( "god.out", "w", stdout );
    
        int T; init();
        for ( scanf( "%d", &T ); T--; sgt.node = 0 ) {
            scanf( "%d %d", &n, &q );
            rep ( i, 1, n ) {
                int t; scanf( "%d", &t );
                sgt.insert( root[i] = root[i - 1], 1, n, t );
            }
    
            for ( int l1, r1, l2, r2; q--; ) {
                scanf( "%d %d %d %d", &l1, &r1, &l2, &r2 );
                int rt1[] = { root[l1 - 1], root[r1] },
                  rt2[] = { root[l2 - 1], root[r2] };
                int mxl = sgt.prefix( rt1[0], rt1[1], 1, n, n ),
                  mxr = sgt.prefix( rt2[0], rt2[1], 1, n, n ), cnt = 0, ans = 1;
                while ( mxl || mxr ) {
                    if ( mxl < mxr ) {
                        int lef = sgt.prefix( rt1[0], rt1[1], 1, n, mxr ),
                          len = sgt.count( rt2[0], rt2[1], 1, n, lef, mxr );
                        cnt += len;
                        mxr = sgt.prefix( rt2[0], rt2[1], 1, n, lef );
                    } else {
                        int lef = sgt.prefix( rt2[0], rt2[1], 1, n, mxl ),
                          len = sgt.count( rt1[0], rt1[1], 1, n, lef, mxl );
                        if ( cnt < len ) { ans = 0; break; }
                        ans = mul( ans, mul( fac[cnt], ifac[cnt - len] ) );
                        cnt -= len;
                        mxl = sgt.prefix( rt1[0], rt1[1], 1, n, lef );
                    }
                }
                printf( "%d
    ", ans );
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    【控件推荐】Html编辑器控件 CuteEditor
    【ASP.NET】网页中嵌入视频
    【经验分享】ASP.NET 项目中用到的广告效果
    【转贴好文】服务器概述
    【经验分享】取某月的最后一天的方法
    【经验分享】Word无法使用鼠标选中问题解决
    【经验分享】Sqlserver和Oracle混合事务
    【编码之外】2009春节前最后一天班,感谢一下帮助过我的朋友
    【转贴好文】做快乐的程序员
    【经验分享】JavaScript 中的事件说明
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14983828.html
Copyright © 2011-2022 走看看