Create

本文介绍了一种使用颜色段和可持久化线段树解决区间查询与更新问题的方法。通过均摊分析颜色段并利用set维护,实现了高效的区间赋值及查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

一个序列,有很多询问,每个询问要问区间>=x的数的个数。
现有若干修改操作,区间赋值,每次修改后请你将所有询问得到的答案和输出。

颜色段

均摊分析颜色段!
可以用set维护颜色段。
然后只需要考虑一个区间全部由x变成y产生代价。
先把询问按x排序做可持久化线段树,然后就很好做。

#pragma GCC optimize(2)
#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10,maxtot=24000000+10;
int pre[maxn*4],nxt[maxn*4],L[maxn*4],R[maxn*4],val[maxn*4];
struct dong{
    int l,r,x;
} ask[maxn];
struct suan{
    int x,y;
    friend bool operator <(suan a,suan b){
        return a.x<b.x||a.x==b.x&&a.y<b.y;
    }
} zlt;
multiset<suan> s1;
ll tree[maxtot];
int a[maxn],root[maxn],left[maxtot],right[maxtot],ad[maxtot],sta[80];
int i,j,k,l,r,x,y,xx,yy,s,t,n,m,q,tot,top,cnt;
ll ans,LL,rr,tt;
bool czy;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int newnode(int x){
    tot++;
    left[tot]=left[x];
    right[tot]=right[x];
    tree[tot]=tree[x];
    ad[tot]=ad[x];
    return tot;
}
void mark(int &x,int l,int r,int v){
    x=newnode(x);
    tree[x]+=(ll)(r-l+1)*v;
    ad[x]+=v;
}
void down(int x,int l,int r){
    int mid=(l+r)/2;
    if (ad[x]){
        mark(left[x],l,mid,ad[x]);
        mark(right[x],mid+1,r,ad[x]);
        ad[x]=0;
    }
}
void insert(int &x,int l,int r,int a,int b){
    //x=newnode(x);
    if (l==a&&r==b){
        mark(x,l,r,1);
        return;
    }
    down(x,l,r);
    x=newnode(x);
    int mid=(l+r)/2;
    if (b<=mid) insert(left[x],l,mid,a,b);
    else if (a>mid) insert(right[x],mid+1,r,a,b);
    else{
        insert(left[x],l,mid,a,mid);
        insert(right[x],mid+1,r,mid+1,b);
    }
    tree[x]=tree[left[x]]+tree[right[x]];
}
ll query(int x,int l,int r,int a,int b){
    //if (!x) return 0;
    if (l==a&&r==b) return tree[x];
    down(x,l,r);
    int mid=(l+r)/2;
    if (b<=mid) return query(left[x],l,mid,a,b);
    else if (a>mid) return query(right[x],mid+1,r,a,b);
    else return query(left[x],l,mid,a,mid)+query(right[x],mid+1,r,mid+1,b);
}
void change(int l,int r,int x,int y,int f){
    if (x==y) return;
    if (x>y) swap(x,y),f*=-1;
    ll t=query(root[x+1],1,n,l,r)-query(root[y+1],1,n,l,r);
    ans+=t*f;
}
bool cmp(dong a,dong b){
    return a.x<b.x;
}
void write(ll x){
    if (!x){
        putchar('0');
        putchar('\n');
        return;
    }
    top=0;
    while (x){
        sta[++top]=x%10;
        x/=10;
    }
    while (top) putchar('0'+sta[top--]);
    putchar('\n');
}
int main(){
    freopen("create.in","r",stdin);freopen("create.out","w",stdout);
    n=read();m=read();q=read();
    czy=1;
    cnt=0;
    fo(i,1,n){
        a[i]=read();
        if (a[i]!=a[i-1]){
            R[cnt]=i-1;
            L[++cnt]=i;
            pre[cnt]=cnt-1;
            nxt[cnt-1]=cnt;
            val[cnt]=a[i];
            zlt.x=R[cnt-1];
            zlt.y=cnt-1;
            s1.insert(zlt);
        }
    }
    R[cnt]=n;
    zlt.x=n;
    zlt.y=cnt;
    s1.insert(zlt);
    fo(i,1,m){
        ask[i].l=read();ask[i].r=read();
        ask[i].x=read();
    }
    sort(ask+1,ask+m+1,cmp);
    j=m;
    fd(i,n,1){
        root[i]=root[i+1];
        while (j&&ask[j].x==i){
            insert(root[i],1,n,ask[j].l,ask[j].r);
            j--;
        }
    }
    fo(i,1,cnt)
        change(L[i],R[i],0,val[i],1);
    //printf("%lld\n",ans);
    write(ans);
    //return 0;
    while (q--){
        LL=read();rr=read();tt=read();
        if (czy){
            LL^=ans;
            rr^=ans;
            tt^=ans;
        }
        l=LL;r=rr;t=tt;
        zlt.x=l;zlt.y=0;
        x=(*s1.lower_bound(zlt)).y;
        zlt.x=r;zlt.y=0;
        y=(*s1.lower_bound(zlt)).y;
        if (x==y){
            change(l,r,val[x],t,1);
            zlt.x=R[x];zlt.y=x;
            s1.erase(s1.find(zlt));
            if (l!=L[x]){
                cnt++;
                R[cnt]=l-1;
                L[cnt]=L[x];
                val[cnt]=val[x];
                zlt.x=R[cnt];zlt.y=cnt;
                s1.insert(zlt);
                xx=cnt;
                pre[cnt]=pre[x];
                if (pre[x]) nxt[pre[x]]=cnt;
            }
            else xx=pre[x];
            if (r!=R[x]){
                cnt++;
                R[cnt]=R[x];
                L[cnt]=r+1;
                val[cnt]=val[x];
                zlt.x=R[cnt];zlt.y=cnt;
                s1.insert(zlt);
                yy=cnt;
                nxt[cnt]=nxt[x];
                if (nxt[x]) pre[nxt[x]]=cnt;
            }
            else yy=nxt[x];
            L[++cnt]=l;
            R[cnt]=r;
            val[cnt]=t;
            zlt.x=r;zlt.y=cnt;
            s1.insert(zlt);
            pre[cnt]=xx;
            if (xx) nxt[xx]=cnt;
            nxt[cnt]=yy;
            if (yy) pre[yy]=cnt;
            //printf("%lld\n",ans);
            write(ans);
            continue;
        }
        change(l,R[x],val[x],t,1);
        zlt.x=R[x];zlt.y=x;
        s1.erase(s1.find(zlt));
        change(L[y],r,val[y],t,1);
        zlt.x=R[y];zlt.y=y;
        s1.erase(s1.find(zlt));
        j=nxt[x];
        while (j!=y){
            change(L[j],R[j],val[j],t,1);
            zlt.x=R[j];zlt.y=j;
            s1.erase(s1.find(zlt));
            j=nxt[j];
        }
        if (l!=L[x]){
            R[x]=l-1;
            zlt.x=R[x];zlt.y=x;
            s1.insert(zlt);
            xx=x;
        }
        else xx=pre[x];
        if (r!=R[y]){
            L[y]=r+1;
            zlt.x=R[y];zlt.y=y;
            s1.insert(zlt);
            yy=y;
        }
        else yy=nxt[y];
        cnt++;
        L[cnt]=l;
        R[cnt]=r;
        val[cnt]=t;
        pre[cnt]=xx;
        if (xx) nxt[xx]=cnt;
        nxt[cnt]=yy;
        if (yy) pre[yy]=cnt;
        zlt.x=r;zlt.y=cnt;
        s1.insert(zlt);
        //printf("%lld\n",ans);
        write(ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值