UOJ #671. 【UNR #5】诡异操作
题面传送门
首先当除法中可以直接舍去。否则每个数最多会被除次。所以暴力除就好了。
与操作可以线段树上每个节点维护这个区间内每一位有几个。然后懒标记下放即可。
时间复杂度,但是因为过不去。
考虑如何优化。可以发现每次暴力除以后需要重新对每个数拆位,并且每次Update的时候每个int内一部分是空的,无法并行。
又可以发现我们每个线段树节点存储了一个的矩阵,我们每次并行计算优化的是
所以可以把这个矩阵反过来,用个数,第个数表示每一位二进制的个数在该二进制表示下有没有这一位。
这样每次暴力除的时候直接把除完的数放在第个数即可,这一部分时间复杂度变为。
并且Update的时候我们可以从低位往高位做,用异或算剩下位,用与和或算进位。这样这一部分时间复杂度变成
总时间复杂度,注意常数,卡常卡了一晚上。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 300000
#define M 500000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
using namespace std;typedef __uint128_t u128;
int n,m,k,x,y,lg[N+5],op;u128 A[N+5],w,Ans;const u128 INF=-1;
I u128 read() {static char buf[100];scanf("%s", buf);u128 res=0;for(int i=0;buf[i];++i) res=res<<4|(buf[i]<='9'?buf[i]-'0':buf[i]-'a'+10);return res;}
I void print(u128 res) {if(res>=16)print(res/16);putchar(res%16>=10?'a'+res%16-10:'0'+res%16);}
namespace Tree{
#define ls now<<1
#define rs now<<1|1
u128 Pa[N+5<<5],*H=Pa,*F[N+5<<2],Fl[N+5<<2];char S[N+5<<2],G[N+5<<2];I void Up(int now){u128 Ns=0;for(RI i=0;i<=S[now];i++) F[now][i]=F[ls][i]^F[rs][i]^Ns,Ns=(Ns&(F[ls][i]|F[rs][i]))|(F[ls][i]&F[rs][i]);G[now]=G[ls]&G[rs];}
I void BD(int l=1,int r=n,int now=1){F[now]=H;S[now]=lg[r-l+1];H+=S[now]+2;Fl[now]=INF;if(l==r) {F[now][0]=A[l];G[now]=(!A[l]);return;}int m=l+r>>1;BD(l,m,ls);BD(m+1,r,rs);Up(now);}
I void PF(int now,u128 w){for(RI i=0;i<=S[now];i++) F[now][i]&=w;Fl[now]&=w;}I void P(int now){Fl[now]^INF&&(PF(ls,Fl[now]),PF(rs,Fl[now]),Fl[now]=INF);}
I void Div(int l=1,int r=n,int now=1){if(G[now])return;if(l==r) {F[now][0]/=w;G[now]=(!F[now][0]);return;}int m=l+r>>1;P(now);x<=m&&(Div(l,m,ls),0);y>m&&(Div(m+1,r,rs),0);Up(now);}
I void And(int l=1,int r=n,int now=1){if(G[now])return;if(x<=l&&r<=y) return PF(now,w);P(now);int m=l+r>>1;x<=m&&(And(l,m,ls),0);y>m&&(And(m+1,r,rs),0);Up(now);}
I void Qry(int x,int y,int l=1,int r=n,int now=1){if(G[now]) return;if(x<=l&&r<=y){for(RI i=0;i<=S[now];i++) Ans+=F[now][i]<<i;return;}int m=l+r>>1;P(now);x<=m&&(Qry(x,y,l,m,ls),0);y>m&&(Qry(x,y,m+1,r,rs),0);}
#undef ls
#undef rs
}
int main(){
//freopen("1.in","r",stdin);freopen("1.out","w",stdout);
RI i;scanf("%d%d",&n,&m);for(i=2;i<=n;i++) lg[i]=lg[i/2]+1;for(i=1;i<=n;i++) A[i]=read();Tree::BD();while(m--)scanf("%d%d%d",&op,&x,&y),op==1?(w=read(),w^1&&(Tree::Div(),0)):(op^3?(w=read(),Tree::And(),0):(Ans=0,Tree::Qry(x,y),print(Ans),Pc('\n')));
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】