Comet OJ - Contest #14 (D转转的数据结构题) set+树状数组
有一个长度为 m 的整数序列 c,初始值都是 0
还有一个长度为 n 的操作序列,第 i 个元素用三元组 (li,ri,vi) 描述,代表将 c[li]∼c[ri] 都赋值为 vi
有 q 个询问,第 i 次询问让你求出执行第 xi 到 yi 这 yi−xi+1 个操作后序列所有整数的和.
题解:
首先,我们按照询问的右端点 r 排序,然后依次执行时刻小于等于当前右端点的操作.
我们要查的显然就是序列中被覆盖的时间戳在 [l,r] 之间的所有元素和.
然后就有一个套路了:我们维护四元组 (l,r,v,k) 表示在第 k 时刻时将 [l,r] 置为 v.
如果一个位置在多个时刻都被覆盖,我们就保留修改时刻最大的那个.
所以,我们发现所有的四元组是互不相交的.
考虑插入一个新的操作:(li,ri,vi),我们先找到是否有四元组盖住 li/ri,如果有的话就都分成两个,然后再扔回 set 中.
然后,我们再把所有在 [li,ri] 之间的四元组全删掉,然后插入新的四元组.
这个做法看起来十分暴力,但是我们分析一下复杂度:
每次插入最多会新生成 3 个四元组,而一个四元组被删除后就再也不会回来.
所以总插入数量和总删除数量不超过 6n,是线性的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include <cstdio> #include <set> #include <map> #include <vector> #include <algorithm> #include <cstring> #include <string> #define N 500009 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; namespace BIT { ll c[N]; int lowbit( int t) { return t&(-t); } ll query( int x) { ll re=0; for (;x>0;x-=lowbit(x)) re+=c[x]; return re; } void update( int x,ll v) { for (;x<N;x+=lowbit(x)) c[x]+=v; } }; int n,m,Q; ll answer[N]; struct node { int l,r,v,d; node( int l=0, int r=0, int v=0, int d=0):l(l),r(r),v(v),d(d){} bool operator<(node b) const { return l<b.l; } }a[N],cn[N]; set<node>se; set<node>::iterator t; struct ask{ int l,r,id; }as[N]; bool cmp(ask a,ask b) { return a.r<b.r; } void split(node a, int pos) { if (a.l==a.r||pos<=a.l||pos>a.r) return ; node p=a; se.erase(a); p.l=pos,a.r=pos-1; se.insert(a); se.insert(p); } void Insert(node a) { int l=a.l,r=a.r,v=a.v,d=a.d,tot=0; set<node>::iterator itl,itr,it; itl=se.lower_bound(node(l+1,0,0,0)); if (itl!=se.begin()) --itl,split(*itl,l); itr=se.lower_bound(node(r+1,0,0,0)); if (itr!=se.begin()) --itr,split(*itr,r+1); itl=se.lower_bound(node(l,0,0,0)); itr=se.lower_bound(node(r+1,0,0,0)); for (it=itl;it!=itr;it++) { BIT::update((*it).d,-(ll)((*it).r-(*it).l+1)*(*it).v); cn[++tot]=*it; } for ( int i=1;i<=tot;++i) se.erase(cn[i]); BIT::update(a.d,(ll)(a.r-a.l+1)*a.v); se.insert(a); } int main() { // setIO("input"); int i,j; scanf ( "%d%d%d" ,&n,&m,&Q); for (i=1;i<=n;++i) scanf ( "%d%d%d" ,&a[i].l,&a[i].r,&a[i].v),a[i].d=i; for (i=1;i<=Q;++i) scanf ( "%d%d" ,&as[i].l,&as[i].r),as[i].id=i; sort(as+1,as+1+Q,cmp); for (j=i=1;i<=Q;++i) { for (;j<=n&&a[j].d<=as[i].r;++j) Insert(a[j]); answer[as[i].id]=BIT::query(as[i].r)-BIT::query(as[i].l-1); } for (i=1;i<=Q;++i) printf ( "%lld\n" ,answer[i]); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步