【前言】
这个题想的时候想错了几次,后面看了别人的blog才发现偏差。
【题目】
LOJ
初始有一棵线段树,没有标记,对于一次操作 [ l , r ] [l,r] [l,r],将所有线段树复制一份,对于奇数标号的所有线段树,我们像普通线段树一样给区间打上标记, pushdown \text{pushdown} pushdown函数会将标记下放并将这个节点的标记情况。每次询问所有拥有的线段树一共有多少个节点有标记。
n , Q ≤ 1 0 5 n,Q\leq 10^5 n,Q≤105
【解题思路】
对于每一次操作,不妨考虑对节点的情况分类统计贡献。以下称“被定位”为 q l ≤ l ≤ r ≤ q r ql\leq l\leq r\leq qr ql≤l≤r≤qr的节点,我们大概可以根据操作区间将节点分为如下几个类
考虑这次操作对贡献的影响:
考虑维护 f i f_i fi:
那么线段树维护节点权值(只需要维护乘法标记,因为加法只是对于这个节点自己加),以及 f f f的值(需要维护加标记和乘标记)。
复杂度 O ( n log n ) O(n\log n) O(nlogn)
【参考代码】
#include
using namespace std;
const int N=1e5+10,mod=998244353;
int pw,ans,delta;
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x>9)write(x/10);putchar(x%10^48);}
void writeln(int x){write(x);putchar('\n');}
}
using namespace IO;
namespace Math
{
int upm(int x){return x>=mod?x-mod:(x<0?x+mod:x);}
void up(int &x,int y){x=upm(x+y);}
int mul(int x,int y){return 1ll*x*y%mod;}
}
using namespace Math;
namespace Data_Structure
{
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
struct node
{
int v,mulv,f,addf,mulf;
}t[N<<2];
void build(int x,int l,int r)
{
t[x].mulv=t[x].mulf=1;
if(l==r) return;
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void multv(int x,int v){t[x].v=mul(t[x].v,v);t[x].mulv=mul(t[x].mulv,v);}
void multf(int x,int v){t[x].f=mul(t[x].f,v);t[x].mulf=mul(t[x].mulf,v);t[x].addf=mul(t[x].addf,v);}
void addtf(int x,int v){up(t[x].f,v);up(t[x].addf,v);}
void pushdown(int x)
{
if(t[x].mulv>1) multv(ls,t[x].mulv),multv(rs,t[x].mulv),t[x].mulv=1;
if(t[x].mulf>1) multf(ls,t[x].mulf),multf(rs,t[x].mulf),t[x].mulf=1;
if(t[x].addf>0) addtf(ls,t[x].addf),addtf(rs,t[x].addf),t[x].addf=0;
}
void update(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
up(ans,-t[x].v);up(t[x].v,pw);up(t[x].mulv,t[x].mulv);
addtf(x,pw);up(delta,t[x].v);
return;
}
if(L>r || R<l)
{
up(ans,-t[x].v);up(t[x].v,t[x].f);up(t[x].mulv,t[x].mulv);
multf(x,2);up(delta,t[x].v);
return;
}
pushdown(x);up(ans,-t[x].v);up(delta,t[x].v);
int mid=(l+r)>>1;
update(ls,l,mid,L,R);update(rs,mid+1,r,L,R);
}
#undef ls
#undef rs
}T;
}
using namespace Data_Structure;
namespace DreamLolita
{
int n,Q;
void solution()
{
n=read();Q=read();pw=1;
T.build(1,1,n);
while(Q--)
{
int op=read(),l,r;
if(op&1)
{
l=read();r=read();delta=0;
T.update(1,1,n,l,r);//printf("%d %d %d\n",ans,delta,pw);
up(ans,ans);up(ans,delta);up(pw,pw);
}
else writeln(ans);
}
}
}
int main()
{
#ifdef Durant_Lee
freopen("LOJ3043.in","r",stdin);
freopen("LOJ3043.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}