[ZJOI2019]线段树
[ZJOI2019]线段树
对于一次询问,假设之前有\(k\)次修改,则有\(2^k\)棵线段树(每种操作执行或者不执行)。
于是我们考虑用线段树维护\(\text{DP}\)。
设\(f(x)\)表示\(x\)节点在之前的\(f(x)\)棵树中有标记。设\(g(x)\)表示\(x\)在之前的\(g(x)\)棵树中祖先节点中没有标记。
具体维护的时候将线段树上的所有节点点分成了\(5\)类,然后分别维护。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 100005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
const ll mod=998244353;
ll ksm(ll t,ll x) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
}
int n,m;
ll ans;
ll pw2[N];
int tim;
struct tree {
int l,r;
ll f,g,sum;
ll mulg;
ll mul;
}tr[N<<3];
void build(int v,int l,int r) {
tr[v].l=l,tr[v].r=r;
tr[v].g=1;
tr[v].mul=tr[v].mulg=1;
if(l==r) return ;
int mid=l+r>>1;
build(v<<1,l,mid),build(v<<1|1,mid+1,r);
}
void update(int v) {tr[v].sum=(tr[v<<1].sum+tr[v<<1|1].sum+tr[v].f)%mod;}
void Mul(int v,ll flag) {
tr[v].mul=tr[v].mul*flag%mod;
tr[v].f=tr[v].f*flag%mod;
tr[v].sum=tr[v].sum*flag%mod;
}
void Mulg(int v,ll flag) {
tr[v].g=tr[v].g*flag%mod;
tr[v].mulg=tr[v].mulg*flag%mod;
}
void down(int v) {
if(tr[v].mul!=1) {
Mul(v<<1,tr[v].mul);
Mul(v<<1|1,tr[v].mul);
tr[v].mul=1;
}
if(tr[v].mulg!=1) {
Mulg(v<<1,tr[v].mulg);
Mulg(v<<1|1,tr[v].mulg);
tr[v].mulg=1;
}
}
void Modify(int v,int l,int r) {
if(tr[v].l!=tr[v].r) down(v);
if(tr[v].l>r||tr[v].r<l) {
(tr[v].f+=pw2[tim]-tr[v].g+mod)%=mod;
(tr[v].g+=tr[v].g)%=mod;
Mulg(v<<1,2),Mulg(v<<1|1,2);
Mul(v<<1,2),Mul(v<<1|1,2);
} else if(l<=tr[v].l&&tr[v].r<=r) {
(tr[v].f+=pw2[tim])%=mod;
Mul(v<<1,2),Mul(v<<1|1,2);
} else {
(tr[v].g+=pw2[tim])%=mod;
Modify(v<<1,l,r),Modify(v<<1|1,l,r);
}
update(v);
}
int main() {
pw2[0]=1;
for(int i=1;i<=100000;i++) pw2[i]=pw2[i-1]*2%mod;
n=Get(),m=Get();
build(1,1,n);
int op;
int l,r;
while(m--) {
op=Get();
if(op==1) {
l=Get(),r=Get();
Modify(1,l,r);
tim++;
} else {
cout<<tr[1].sum<<"\n";
}
}
return 0;
}