【WinterCamp 2013】阿凡达

Description

维护一个序列,资瓷
1:将A[l]~A[r]中的每一个A[x]变为(x-l+1)*a mod b
2:询问A[l]~A[r]的和

n<=1e9,m<=5*1e4

Solution

考虑将一次赋值看做一个颜色段,然后同一个颜色段里面的和我们可以用类欧来计算。
用线段树维护是log^2的,但我们其实有一种更加优美的写法
我们可以用一棵平衡树来维护每一个颜色端,这样子复杂度就变成了一个log了。
但是比线段树难写多了QwQ

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef unsigned long long ll;

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

void write(ll x) {
    if (!x) {puts("0");return;}
    char ch[20];int tot=0;
    for(;x;x/=10) ch[++tot]=x%10+'0';
    fd(i,tot,1) putchar(ch[i]);
    puts("");
}

const int N=2*1e5+5;

ll Sum[N],Key[N];
int L[N],R[N],St[N],A[N],B[N],f[N],t[N][2],tot;
int n,q,a,b,opt,l,r,root;

ll sum(ll n) {return (n&1)?((n+1)/2*n):(n/2*(n+1));}

ll solve(ll a,ll b,ll c,ll n) {
    ll m=(a*n+b)/c;
    if (!a) return b/c*n;
    if (!m) return 0;
    if (a<c&&b<c) return n*m-solve(c,c-b-1,a,m-1);
    ll res=0;
    if (a>=c) res+=a/c*sum(n),a%=c;
    if (b>=c) res+=b/c*(n+1),b%=c;
    return res+solve(a,b,c,n);
}

ll calc(int n,int a,int b) {
    ll res=(ll)a*sum(n);
    return res-(ll)b*solve(a,0,b,n);
}

int son(int x) {return t[f[x]][1]==x;}

void updata(int x) {Sum[x]=Sum[t[x][0]]+Sum[t[x][1]]+Key[x];}

void rotate(int x) {
    int y=f[x],z=son(x);
    if (f[y]) t[f[y]][son(y)]=x;
    if (t[x][1-z]) f[t[x][1-z]]=y;
    f[x]=f[y];f[y]=x;
    t[y][z]=t[x][1-z];t[x][1-z]=y;
    updata(y);updata(x);
}

void splay(int x,int y) {
    while (f[x]!=y) {
        if (f[f[x]]!=y)
            if (son(x)==son(f[x])) rotate(f[x]);
            else rotate(x);
        rotate(x);
    }
    if (!y) root=x;
}

int find(int x,int k) {
    if (L[x]<=k&&k<=R[x]) return x;
    if (R[x]<k) return find(t[x][1],k);
    else return find(t[x][0],k);
}

void modify(int x) {
    Key[x]=calc(R[x]-St[x]+1,A[x],B[x])-calc(L[x]-St[x],A[x],B[x]);
    if (f[x]) splay(x,0);
}

void insert(int &x,int now,int fa) {
    if (!x) {
        x=now;
        f[x]=fa;
        splay(x,0);
        return;
    }
    if (R[x]<L[now]) insert(t[x][1],now,x);
    else insert(t[x][0],now,x);
}

int main() {
    n=read();q=read();
    L[root=tot=1]=1;R[tot]=n;B[tot]=1000000;St[tot]=1;
    for(;q;q--) {
        opt=read();l=read();r=read();
        if (opt==1) {
            a=read();b=read();
            int posl=find(root,l);splay(posl,0);
            int posr=find(root,r);
            if (posl!=posr) {
                splay(posr,posl);
                f[t[posr][0]]=0;t[posr][0]=0;
                if (R[posl]+1!=L[posr]) {
                    A[++tot]=a;B[tot]=b;St[tot]=l;
                    L[tot]=R[posl]+1;R[tot]=L[posr]-1;
                    modify(tot);
                    insert(root,tot,0);
                }
                if (l==L[posl]) {
                    A[posl]=a;B[posl]=b;St[posl]=l;
                    modify(posl);
                } else {
                    A[++tot]=a;B[tot]=b;St[tot]=l;
                    L[tot]=l;R[tot]=R[posl];
                    R[posl]=l-1;
                    modify(tot);modify(posl);
                    insert(root,tot,0);
                }
                if (r==R[posr]) {
                    A[posr]=a;B[posr]=b;St[posr]=l;
                    modify(posr);
                } else {
                    A[++tot]=a;B[tot]=b;St[tot]=l;
                    L[tot]=L[posr];R[tot]=r;
                    L[posr]=r+1;
                    modify(tot);modify(posr);
                    insert(root,tot,0);
                }
            } else {
                if (l==L[posl]&&r==R[posl]) {
                    A[posl]=a;B[posl]=b;St[posl]=l;
                    modify(posl);
                } else {
                    if (l!=L[posl]) {
                        A[++tot]=A[posl];B[tot]=B[posl];St[tot]=St[posl];
                        L[tot]=L[posl];R[tot]=l-1;
                        L[posl]=l;
                        modify(tot);modify(posl);
                        insert(root,tot,0);
                    }
                    if (r!=R[posl]) {
                        A[++tot]=A[posl];B[tot]=B[posl];St[tot]=St[posl];
                        L[tot]=r+1;R[tot]=R[posl];
                        R[posl]=r;
                        modify(tot);modify(posl);
                        insert(root,tot,0);
                    }
                    A[posl]=a;B[posl]=b;St[posl]=l;
                    modify(posl);
                }
            }
        }
        if (opt==2) {
            int posl=find(root,l);splay(posl,0);
            int posr=find(root,r);
            ll ans=0;
            if (posl!=posr) {
                splay(posr,posl);
                ans=Sum[t[posr][0]];
                ans+=calc(R[posl]-St[posl]+1,A[posl],B[posl])-
                calc(l-St[posl],A[posl],B[posl]);
                ans+=calc(r-St[posr]+1,A[posr],B[posr])
                -calc(L[posr]-St[posr],A[posr],B[posr]);
            } else ans=calc(r-St[posl]+1,A[posl],B[posl])-
            calc(l-St[posl],A[posl],B[posl]);
            write(ans);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值