UOJ46 清华集训2014 玄学 二进制分组、二分

传送门


注意到操作是可分裂、可合并的,所以一个很简单的想法是使用线段树维护每一个区间的答案。

虽然对于线段树上每个节点对应的操作序列中,区间的每一个位置的变换之间有可能有不同,但是至多只会存在区间长度种变换方式。我们可以在pushup的时候计算出这区间长度种变换的方式和这些方式对应的区间,这样每一次询问就只需要依次在当前查询区间对应的\(log\)个线段树的区间上二分出这个位置对应的变换方式就可以得到答案。

但是每一次都pushup显然太慢,不难注意到对于线段树上的区间\([l,r]\)只有当下标在\(l \sim r\)的所有操作都加入线段树之后,这个区间才有可能被询问到,所以我们使用二进制分组的思路,只在某一个区间的\(r\)位置插入操作的时候对这个区间pushup。这样我们可以得到复杂度为\(O(nlogn+qlog^2n)\)

#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar(); bool f = 0;
    while(!isdigit(c)){f = c == '-'; c = getchar();}
    while(isdigit(c)){
        a = a * 10 + c - 48; c = getchar();
    }
    return f ? -a : a;
}

#define sz(x) (int)x.size()
const int _ = 1e5 + 7;
int M , N , arr[_] , lastans = 0 , cnt = 0;
struct node{int mn , a , b; friend bool operator <(node A , node B){return A.mn < B.mn;}};
namespace segt{
    vector < node > nd[_ << 2];

#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
    
    void ins(int x , int l , int r , int tar , int l1 , int r1 , int a , int b){
        if(l == r){
            nd[x].push_back((node){0 , 1 , 0}); nd[x].push_back((node){l1 , a , b});
            nd[x].push_back((node){r1 + 1 , 1 , 0}); nd[x].push_back((node){(int)1e9 , 0 , 0});
            return;
        }
        mid >= tar ? ins(lch , l , mid , tar , l1 , r1 , a , b) : ins(rch , mid + 1 , r , tar , l1 , r1 , a , b);
        if(r == tar){
            vector < node > &l = nd[lch] , &r = nd[rch]; int pl = 0 , pr = 0;
            while(pl + 1 < sz(l) || pr + 1 < sz(r)){
                nd[x].push_back((node){max(l[pl].mn , r[pr].mn) , 1ll * l[pl].a * r[pr].a % M , (1ll * l[pl].b * r[pr].a + r[pr].b) % M});
                if(l[pl + 1].mn == r[pr + 1].mn){++pl; ++pr;}
                else l[pl + 1].mn < r[pr + 1].mn ? ++pl : ++pr;
            }
            nd[x].push_back((node){(int)1e9 , 0 , 0});
        }
    }
    
    void qry(int x , int l , int r , int L , int R , int pos , int &val){
        if(l >= L && r <= R){
            auto t = upper_bound(nd[x].begin() , nd[x].end() , (node){pos , 0 , 0}) - 1;
            val = (1ll * val * t->a + t->b) % M; return;
        }
        if(mid >= L) qry(lch , l , mid , L , R , pos , val);
        if(mid < R) qry(rch , mid + 1 , r , L , R , pos , val);
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    int id = read(); N = read(); M = read();
    for(int i = 1 ; i <= N ; ++i) arr[i] = read();
    for(int Q = read() ; Q ; --Q)
        if(read() == 1){
            int i = read() ^ ((id & 1) * lastans) , j = read() ^ ((id & 1) * lastans) , a = read() , b = read();
            segt::ins(1 , 1 , 1e5 , ++cnt , i , j , a , b);
        }
        else{
            int i = read() ^ ((id & 1) * lastans) , j = read() ^ ((id & 1) * lastans) , k = read() ^ ((id & 1) * lastans);
            int val = arr[k]; segt::qry(1 , 1 , 1e5 , i , j , k , val); printf("%d\n" , lastans = val);
        }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/11507749.html