[UOJ46][清华集训2014]玄学

uoj

description

给出\(n\)个变换,第\(i\)个变换是将区间中\(l_i,r_i\)的数\(x\)变成\((a_ix+b_i)\mod m\)
每次会新增一个变换,或者查询询问如果进行编号\([s,t]\)的操作,第\(k\)个数会变成多少。
\(n\le10^5,q\le6\times10^5\)

sol

二进制分组。
按顺序把变化插入线段树,如果线段树的某个满了就向上归并两个儿子的变换。
\(a_j(a_ix+b_i)+b_j=a_ia_jx+a_jb_i+b_j\)就是两个变换的合并。
查询的时候找到线段树的对应节点(这些节点一定都是合并好了的),然后在维护出的变化序列上二分找到第\(k\)个位置,直接算即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e5+5;
struct node{int p,a,b;}t[N*30];
int Type,n,m,q,mod,val[N],L[N<<2],R[N<<2],cnt,ans;
void modify(int x,int l,int r,int ql,int qr,int a,int b){
    if (l==r){
        L[x]=cnt+1;
        if (ql>1) t[++cnt]=(node){ql-1,1,0};
        t[++cnt]=(node){qr,a,b};
        if (qr<n) t[++cnt]=(node){n,1,0};
        R[x]=cnt;return;
    }
    int mid=l+r>>1;
    if (m<=mid) modify(x<<1,l,mid,ql,qr,a,b);
    else modify(x<<1|1,mid+1,r,ql,qr,a,b);
    if (m<r) return;
    int i=L[x<<1],j=R[x<<1],u=L[x<<1|1],v=R[x<<1|1];
    L[x]=cnt+1;
    while (i<=j&&u<=v){
        t[++cnt]=(node){min(t[i].p,t[u].p),1ll*t[i].a*t[u].a%mod,(1ll*t[i].b*t[u].a+t[u].b)%mod};
        if (t[i].p==t[u].p) ++i,++u;else if (t[i].p<t[u].p) ++i;else ++u;
    }
    R[x]=cnt;
}
void calc(int x,int k){
    int l=L[x],r=R[x],res=0;
    while (l<=r){
        int mid=l+r>>1;
        if (t[mid].p>=k) res=mid,r=mid-1;
        else l=mid+1;
    }
    ans=(1ll*ans*t[res].a+t[res].b)%mod;
}
void query(int x,int l,int r,int ql,int qr,int k){
    if (l>=ql&&r<=qr) {calc(x,k);return;}
    int mid=l+r>>1;
    if (ql<=mid) query(x<<1,l,mid,ql,qr,k);
    if (qr>mid) query(x<<1|1,mid+1,r,ql,qr,k);
}
int main(){
    Type=gi()&1;n=gi();mod=gi();
    for (int i=1;i<=n;++i) val[i]=gi();
    q=gi();while (q--){
        int op=gi(),l=gi(),r=gi();
        if (Type) l^=ans,r^=ans;
        if (op==1){
            int a=gi(),b=gi();++m;
            modify(1,1,100000,l,r,a,b);
        }else{
            int k=gi();if (Type) k^=ans;
            ans=val[k];
            query(1,1,100000,l,r,k);
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9452267.html