[Luogu5280][ZJOI2019]线段树(线段树+DP)

https://www.luogu.org/blog/Sooke/solution-p5280

首先想到对线段树上每个点分别维护有多少棵线段树在它上有标记(f[]),然后想到对于每个操作,根据转移的不同分成5种点。

为了满足第三类点的转移要求,再维护g[],转移类似分类讨论即可。

最后发现前三类点是$O(\log n)$级别的,后两类点可以通过打标记实现。于是就做完了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ls (x<<1)
 4 #define rs (ls|1)
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 using namespace std;
 7 
 8 const int N=2000010,mod=998244353;
 9 int n,m,k=1,op,l,r,f[N],g[N],tf[N],tg[N],sf[N];
10 
11 int add(int x,int y){ return x+y>=mod ? x+y-mod : x+y; }
12 int sub(int x,int y){ return x-y<0 ? x-y+mod : x-y; }
13 
14 void upd(int x){ sf[x]=add(f[x],add(sf[ls],sf[rs])); }
15 void pushf(int x,int k){ f[x]=1ll*f[x]*k%mod; tf[x]=1ll*tf[x]*k%mod; sf[x]=1ll*sf[x]*k%mod; }
16 void pushg(int x,int k){ g[x]=1ll*g[x]*k%mod; tg[x]=1ll*tg[x]*k%mod; }
17 
18 void push(int x){
19     if (tf[x]!=1) pushf(ls,tf[x]),pushf(rs,tf[x]),tf[x]=1;
20     if (tg[x]!=1) pushg(ls,tg[x]),pushg(rs,tg[x]),tg[x]=1;
21 }
22 
23 void build(int x,int L,int R){
24     g[x]=tf[x]=tg[x]=1;
25     if (L==R) return;
26     int mid=(L+R)>>1;
27     build(ls,L,mid); build(rs,mid+1,R);
28 }
29 
30 void mdf(int x,int L,int R,int l,int r){
31     push(x);
32     if (L==l && r==R){ f[x]=add(f[x],k); pushf(ls,2); pushf(rs,2); upd(x); return; }
33     int mid=(L+R)>>1; g[x]=add(g[x],k);
34     if (r<=mid){
35         mdf(ls,L,mid,l,r); push(rs); f[rs]=add(f[rs],sub(k,g[rs])); g[rs]=add(g[rs],g[rs]);
36         pushf(rs<<1,2); pushf((rs<<1)|1,2); pushg(rs<<1,2); pushg((rs<<1)|1,2); upd(rs);
37     }else if (l>mid){
38         mdf(rs,mid+1,R,l,r); push(ls); f[ls]=add(f[ls],sub(k,g[ls])); g[ls]=add(g[ls],g[ls]);
39         pushf(ls<<1,2); pushf((ls<<1)|1,2); pushg(ls<<1,2); pushg((ls<<1)|1,2); upd(ls);
40     }else mdf(ls,L,mid,l,mid),mdf(rs,mid+1,R,mid+1,r);
41     upd(x);
42 }
43 
44 int main(){
45     freopen("segment.in","r",stdin);
46     freopen("segment.out","w",stdout);
47     scanf("%d%d",&n,&m); build(1,1,n);
48     rep(i,1,m){
49         scanf("%d",&op);
50         if (op==1) scanf("%d%d",&l,&r),mdf(1,1,n,l,r),k=add(k,k);
51             else printf("%d\n",sf[1]);
52     }
53     return 0;
54 }

 

posted @ 2019-04-14 18:51  HocRiser  阅读(134)  评论(0编辑  收藏  举报