【学习笔记】「UNR #5」诡异操作

在优秀的学长 C202044zxy 讲解下把这道题搞懂了。希望自己也有机会成为学长。

原来线段树还可以这样干!考虑线段树上每个节点用一个数组维护 2 i 2^i 2i的出现次数,也就是二进制下某一位为 1 1 1的数目。这样只看操作一,每个点最多要修改 log ⁡ V \log V logV次,但是线段树上合并左右儿子也有一个 log ⁡ V \log V logV的复杂度,复杂度算上去好像是 O ( n log ⁡ n log ⁡ 2 V ) O(n\log n\log^2 V) O(nlognlog2V)

然后有一个很厉害的 trick \text{trick} trick。考虑之前我们每个节点维护的是权值为 2 i 2^i 2i的数出现的次数,现在我们改成维护出现次数为 2 i 2^i 2i的权值的集合,总之我们构造了一个 log ⁡ n × log ⁡ V \log n\times \log V logn×logV 01 01 01矩阵,把每行拿来维护,发现合并的时候就按行从下往上合并就好了。这个时候复杂度发生了微妙的变化:

1.1 1.1 1.1 每次合并的复杂度从 log ⁡ V \log V logV变成了 log ⁡ n \log n logn
1.2 1.2 1.2 设这个区间长度为 l e n len len,那么只有 2 i ≤ l e n 2^i\le len 2ilen的行才会有值。

现在我们用另一种方法再来算一次复杂度。我们分成普通操作和特殊操作,其中普通操作包括将每个修改区间分成若干个完整的线段树上的区间,并向上合并,这部分复杂度 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n);特殊操作包括对每个完整的区间进行修改(区间所有数除以 v v v),注意到每个点最多被修改 log ⁡ V \log V logV次就会全部变成 0 0 0,并且其合并复杂度应该是 log ⁡ l e n \log len loglen,让计算工具帮我们算一下发现 T ( n ) = 2 T ( n 2 ) + O ( log ⁡ n ) = O ( n ) T(n)=2T(\frac{n}{2})+O(\log n)=O(n) T(n)=2T(2n)+O(logn)=O(n),这样总复杂度 O ( n log ⁡ 2 n + n log ⁡ V ) O(n\log ^2n+n\log V) O(nlog2n+nlogV)就对了。当然我们只是分析了操作一的复杂度,其实操作二的复杂度也是对的,这个可以自己验证。

写了一发,发现之前复杂度之所以算错是因为 操作二的复杂度不需要借助势能来分析,因此从某方面来说操作一和操作二的复杂度计算(或者说操作次数)是独立的。kid_magic 早已意识到了这点,或许这就是神的直觉吧。

这题怎么卡常啊。

用内存池来实现,这样可以把空间优化到 O ( n ) O(n) O(n)。这一点确实比较难想到。

#include<bits/stdc++.h> #define uint __uint128_t using namespace std; const int N=3e5+5; inline uint read() { static char buf[100];uint res=0; scanf("%s",buf); for(int i=0;buf[i];++i) res=res<<4|(buf[i]<='9'?buf[i]-'0':buf[i]-'a'+10); return res; } inline void output(uint res){ if(res>=16)output(res/16); putchar(res%16>=10?'a'+res%16-10:'0'+res%16); } int n,Q; uint a[N],nums[N<<3],*id=nums; struct node{ uint *nums; uint sum; uint lazytags; int tag; uint o; }t[N<<2]; //下传标记(按位与) inline void change(const int p,const int l,const int r,const uint val){ if((t[p].o&val)==t[p].o)return;t[p].o&=val; if(!t[p].tag)t[p].tag=1,t[p].lazytags=val; else t[p].lazytags&=val; int len=r-l+1;t[p].sum=0; for(int i=0;(1<<i)<=len;i++){ t[p].nums[i]&=val; t[p].sum+=(1<<i)*t[p].nums[i]; } } inline void pushdown(const int p,const int l,const int r){ int mid=l+r>>1; if(t[p].tag){ change(p<<1,l,mid,t[p].lazytags); change(p<<1|1,mid+1,r,t[p].lazytags); t[p].tag=0; } } inline void pushup(const int p,const int l,const int r){ int len=r-l+1;uint tmp=0; for(int i=0;(1<<i)<=len;i++){ t[p].nums[i]=t[p<<1].nums[i]^t[p<<1|1].nums[i]^tmp; tmp=(tmp&t[p<<1].nums[i])|(tmp&t[p<<1|1].nums[i])|(t[p<<1].nums[i]&t[p<<1|1].nums[i]); } t[p].sum=t[p<<1].sum+t[p<<1|1].sum; t[p].o=t[p<<1].o|t[p<<1|1].o; } inline void build(const int p,const int l,const int r){ int len=r-l+1; t[p].nums=id;for(int i=0;(1<<i)<=len;i++)id++;id++; if(l==r){ t[p].nums[0]=a[l],t[p].sum=a[l],t[p].o=a[l]; return; } int mid=l+r>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); pushup(p,l,r); } inline void modify(const int p,const int l,const int r,const int ql,const int qr,const uint val){ if(!t[p].o||val==1)return; if(l==r){ t[p].sum/=val,t[p].nums[0]=t[p].sum,t[p].o=t[p].sum; return; } int mid=l+r>>1;pushdown(p,l,r); if(ql<=mid)modify(p<<1,l,mid,ql,qr,val); if(mid<qr)modify(p<<1|1,mid+1,r,ql,qr,val); pushup(p,l,r); } inline void update(const int p,const int l,const int r,const int ql,const int qr,const uint val){ if((t[p].o&val)==t[p].o)return; if(ql<=l&&r<=qr){ change(p,l,r,val); return; } int mid=l+r>>1;pushdown(p,l,r); if(ql<=mid)update(p<<1,l,mid,ql,qr,val); if(mid<qr)update(p<<1|1,mid+1,r,ql,qr,val); pushup(p,l,r); } inline uint query(const int p,const int l,const int r,const int ql,const int qr){ if(ql<=l&&r<=qr)return t[p].sum; int mid=l+r>>1;pushdown(p,l,r); if(qr<=mid)return query(p<<1,l,mid,ql,qr); if(mid<ql)return query(p<<1|1,mid+1,r,ql,qr); return query(p<<1,l,mid,ql,qr)+query(p<<1|1,mid+1,r,ql,qr); } int main() { scanf("%d%d",&n,&Q); for(int i=1;i<=n;i++)a[i]=read(); build(1,1,n); for(int i=1;i<=Q;i++){ int op,l,r;uint v; scanf("%d%d%d",&op,&l,&r); if(op==1){ v=read(); modify(1,1,n,l,r,v); } else if(op==2){ v=read(); update(1,1,n,l,r,v); } else{ output(query(1,1,n,l,r)),puts(""); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529944.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2022-07-04 【学习笔记】图的连通性与回路
2022-07-04 【简要题解】OI Online能力测试校内赛(Round One)T2~T4
2022-07-04 【学习笔记】阶段测试1
点击右上角即可分享
微信分享提示