#include<bits/stdc++.h> #define LL long long #define il inline #define re register #define db double #define eps (1e-5) using namespace std; const int N=500000+10; il LL rd() { LL x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } #define lc (o<<1) #define rc ((o<<1)|1) #define mid ((l+r)>>1) struct node { int wb[3],las; node(){wb[0]=wb[1]=wb[2]=las=0;} }s[N<<2],nw; il node ad(node a,node b) { node an; an.las=(a.las+b.las)%3; for(int i=0;i<3;i++) an.wb[i]=a.wb[i]+b.wb[(i-a.las+3)%3]; return an; } void bui(int o,int l,int r) { if(l==r) { if(rd()&1) s[o].wb[2-(l&1)]=1,s[o].las=2-(l&1); else s[o].wb[0]=1; return; } bui(lc,l,mid),bui(rc,mid+1,r); s[o]=ad(s[lc],s[rc]); } void modif(int o,int l,int r,int lx) { if(l==r) { if(s[o].las) s[o].wb[2-(l&1)]=s[o].las=0,s[o].wb[0]=1; else s[o].wb[2-(l&1)]=1,s[o].las=2-(l&1),s[o].wb[0]=0; return; } if(lx<=mid) modif(lc,l,mid,lx); else modif(rc,mid+1,r,lx); s[o]=ad(s[lc],s[rc]); } node quer(int o,int l,int r,int ll,int rr) { if(ll<=l&&r<=rr) return s[o]; node a,b; if(ll<=mid) a=quer(lc,l,mid,ll,rr); if(rr>mid) b=quer(rc,mid+1,r,ll,rr); return ad(a,b); } int n,m; LL ans; int main() { n=rd(),m=rd(); bui(1,1,n); while(m--) { int op=rd(); if(op&1) modif(1,1,n,rd()); else { ans=0; int l=rd(),r=rd(); nw=quer(1,1,n,l,r);++nw.wb[0]; ans=1ll*nw.wb[0]*(nw.wb[0]-1)/2+1ll*nw.wb[1]*(nw.wb[1]-1)/2+1ll*nw.wb[2]*(nw.wb[2]-1)/2; printf("%lld\n",ans); } } return 0; }详解每一行代码什么意思并代表什么含义
时间: 2024-03-03 12:49:19 浏览: 175
#define的使用技巧
这是一个 C++ 程序,主要实现了一个线段树的模板题目,下面是每一行代码的意思:
```c++
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-5)
using namespace std;
const int N=500000+10;
il LL rd() { //快读函数
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mid ((l+r)>>1)
struct node { //线段树节点结构体
int wb[3],las; //wb:表示三种状态的数量,las:上一次颜色的状态
node(){wb[0]=wb[1]=wb[2]=las=0;} //构造函数
};
il node ad(node a,node b) { //将左右儿子合并成父亲节点
node an;
an.las=(a.las+b.las)%3; //计算父亲节点的颜色状态
for(int i=0;i<3;i++) an.wb[i]=a.wb[i]+b.wb[(i-a.las+3)%3]; //合并三种颜色状态的数量
return an;
}
void bui(int o,int l,int r) { //建树函数
if(l==r) { //叶子节点
if(rd()&1) s[o].wb[2-(l&1)]=1,s[o].las=2-(l&1); //随机生成颜色状态
else s[o].wb[0]=1;
return;
}
bui(lc,l,mid),bui(rc,mid+1,r); //递归建树
s[o]=ad(s[lc],s[rc]); //合并左右儿子的颜色状态
}
void modif(int o,int l,int r,int lx) { //修改函数
if(l==r) { //找到叶子节点
if(s[o].las) s[o].wb[2-(l&1)]=s[o].las=0,s[o].wb[0]=1; //如果上一次颜色状态不是0,则变成0
else s[o].wb[2-(l&1)]=1,s[o].las=2-(l&1),s[o].wb[0]=0; //否则变为1或2
return;
}
if(lx<=mid) modif(lc,l,mid,lx); //如果在左子树中
else modif(rc,mid+1,r,lx); //否则在右子树中
s[o]=ad(s[lc],s[rc]); //合并左右儿子的颜色状态
}
node quer(int o,int l,int r,int ll,int rr) { //查询函数
if(ll<=l&&r<=rr) return s[o]; //如果区间被完全覆盖
node a,b;
if(ll<=mid) a=quer(lc,l,mid,ll,rr); //如果需要查询左子树
if(rr>mid) b=quer(rc,mid+1,r,ll,rr); //如果需要查询右子树
return ad(a,b); //合并左右儿子的颜色状态
}
int n,m; LL ans;
int main() {
n=rd(),m=rd();
bui(1,1,n); //建树
while(m--) {
int op=rd(); //读入操作
if(op&1) modif(1,1,n,rd()); //修改操作
else {
ans=0;
int l=rd(),r=rd();
nw=quer(1,1,n,l,r);++nw.wb[0]; //查询并统计颜色状态数量
ans=1ll*nw.wb[0]*(nw.wb[0]-1)/2+1ll*nw.wb[1]*(nw.wb[1]-1)/2+1ll*nw.wb[2]*(nw.wb[2]-1)/2; //计算答案
printf("%lld\n",ans);
}
}
return 0;
}
```
整个程序主要分为四个部分:
1.建树函数:随机生成每个叶子节点的颜色状态,并递归合并左右儿子的颜色状态。
2.修改函数:找到对应的叶子节点,根据上一次颜色状态,修改为另一种颜色状态,并递归合并左右儿子的颜色状态。
3.查询函数:根据区间范围,递归查询左右儿子的颜色状态,并将结果合并返回。
4.主函数:读入操作和区间范围,进行修改或查询,并统计颜色状态数量,最终计算答案。
阅读全文