Loading

P8512 [Ynoi Easy Round 2021] TEST_152

原题传送门

题意

给定一个长度为 \(m\) 的序列,初始全为 \(0\)。再给 \(n\) 个区间赋值操作。

回答 \(q\) 次询问,每次询问给定 \(L,R\),表示从 \(L\)\(R\) 执行完这 \(R-L+1\) 个操作,求全局和。

询问之间相互独立。


区间推平!直接 I Love Chtholly Tree!

然后考虑如何处理询问。询问是区间的形式,并且询问之间相互独立,所以考虑离线处理类似前缀的东西,或者按端点排序然后扫过去。

考虑 \(ODT\) 维护每次操作对全局和造成的影响,那么现在唯一剩下的问题就是如何处理时间戳。

结合上前面说的处理类似前缀的东西,考虑树状数组维护时间戳。相当于每次操作就是在对应的时间上单点修改记录全局和的变化,查询就是区间查询。

但是这样做的话不同时间的操作可能会互相影响。具体地,比如样例 \(1\) 的前两个操作,第一个是从 \(1\)\(4\) 赋值为 \(3\),第二个是从 \(2\)\(3\) 赋值为 \(1\)。这样的话,第二个操作的区间因为被包含在了第一个里面,所以它在原来基础上对全局和的影响其实并不是它本身带来的贡献,这个时候单独查询操作 \(2\) 就会出错。

所以考虑直接在 \(ODT\) 里面加上时间 \(t\) 一值,因为我们存下的每个颜色段一定对应唯一的一个时间,(即使有两个颜色相同但时间不同的连续段挨在一起,因为不是同一次操作产生的,所以我们也不会把它们合并在一起)那么每次 Assign 的时候就为每个颜色段对应的时间分别在树状数组上做修改即可。

最后一点就是把询问挂在右端点,离线扫过去用树状数组查询即可。

\(\text{Code}:\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define il inline
#define re register
const int N=500500;
int n,m,q,c[N],ans[N],l[N],r[N],x[N];
il int read(){
    re int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
il int lowbit(int x){
    return x&(-x);
}
il void Add(int x,int y){
    if(x<=0)return;
    while(x<=m){
        c[x]+=y;
        x+=lowbit(x);
    }
}
il int Ask(int x){
    int res=0;
    while(x){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
struct Chtholly{
    int l,r,t;
    mutable int val;
    Chtholly(int l,int r=0,int t=0,int val=0):l(l),r(r),t(t),val(val){}
    bool operator<(Chtholly const &a)const{
        return l<a.l;
    }
};
set<Chtholly>s;
#define It set<Chtholly>::iterator
il It Split(int pos){
    It fnd=s.lower_bound(Chtholly(pos));
    if(fnd!=s.end()&&fnd->l==pos)return fnd;
    fnd--;
    if(fnd->r<pos)return s.end();
    int l=fnd->l,r=fnd->r,t=fnd->t,val=fnd->val;
    s.erase(fnd);
    s.insert(Chtholly(l,pos-1,t,val));
    return s.insert(Chtholly(pos,r,t,val)).first;
}//ODT 基本操作
il void Assign(int l,int r,int t,int x){
    It R=Split(r+1),L=Split(l);
    for(re It i=L;i!=R;i++)
        Add(i->t,-(i->r-i->l+1)*i->val);//注意这里是减而不是加
    s.erase(L,R);
    s.insert(Chtholly(l,r,t,x));
    Add(t,(r-l+1)*x);
}
struct query{
    int l,id;
};
vector<query>v[N];
signed main(){
    m=read(),n=read(),q=read();
    s.insert(Chtholly(1,n,0,0));
    for(re int i=1;i<=m;i++)
        l[i]=read(),r[i]=read(),x[i]=read();
    for(re int i=1;i<=q;i++){
        int l=read(),r=read(),id=i;
        v[r].push_back({l,id});//将询问挂在右端点
    }
    for(re int i=1;i<=m;i++){
        Assign(l[i],r[i],i,x[i]);//离线扫描,查询答案。
        for(re auto j:v[i])
            ans[j.id]=Ask(i)-Ask(j.l-1);
    }
    for(re int i=1;i<=q;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

题外话

  • 纪念一下第一道 Ynoi Easy Round.(上次那个是 Ynoi 模拟赛,什么时候才能做正统 Ynoi 啊/kel

  • 在图老师的逼迫下换了洛谷博客的主题和背景,还挺好看的感觉。

posted @ 2023-09-28 08:23  MrcFrst  阅读(16)  评论(0编辑  收藏  举报