P2574 XOR的艺术
题目描述
AKN 觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏。在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下:
- 拥有一个伤害串,是一个长度为 nnn 的只含字符
0和字符1的字符串。规定这个字符串的首字符是第一个字符,即下标从 111 开始。 - 给定一个范围 [l, r][l,~r][l, r],伤害为伤害串的这个范围内中字符
1的个数。 - 会修改伤害串中的数值,修改的方法是把 [l, r][l,~r][l, r] 中所有原来的字符
0变成1,将1变成0。
AKN 想知道一些时刻的伤害,请你帮助他求出这个伤害。
输入格式
输入的第一行有两个用空格隔开的整数,分别表示伤害串的长度 nnn,和操作的个数 mmm。
输入第二行是一个长度为 nnn 的字符串 SSS,代表伤害串。
第 333 到第 (m+2)(m + 2)(m+2) 行,每行有三个用空格隔开的整数 op,l,rop, l, rop,l,r。代表第 iii 次操作的方式和区间,规则是:
- 若 op=0op = 0op=0,则表示将伤害串的 [l, r][l,~r][l, r] 区间内的
0变成1,1变成0。 - 若 op=1op = 1op=1,则表示询问伤害串的 [l, r][l,~r][l, r] 区间内有多少个字符
1。
输出格式
对于每次询问,输出一行一个整数,代表区间内 1 的个数。
输入输出样例 #1
输入 #1
10 6
1011101001
0 2 4
1 1 5
0 3 7
1 1 10
0 1 4
1 2 6
输出 #1
3
6
1
说明/提示
样例输入输出 111 解释
原伤害串为 1011101001。
对于第一次操作,改变 [2, 4][2,~4][2, 4] 的字符,伤害串变为 1100101001。
对于第二次操作,查询 [1, 5][1,~5][1, 5] 内 1 的个数,共有 333 个。
对于第三次操作,改变 [3, 7][3,~7][3, 7] 的字符,伤害串变为 1111010001。
对于第四次操作,查询 [1, 10][1,~10][1, 10] 内 1 的个数,共有 666 个。
对于第五次操作,改变 [1, 4][1,~4][1, 4] 的字符,伤害串变为 0000010001。
对于第六次操作,查询 [2, 6][2,~6][2, 6] 内 1 的个数,共有 111 个。
数据范围与约定
对于 10%10\%10% 的数据,保证 n,m≤10n, m \leq 10n,m≤10。
另有 30%30\%30% 的数据,保证 n,m≤2×103n, m \leq 2 \times 10^3n,m≤2×103。
对于 100%100\%100% 的数据,保证 2≤n,m≤2×1052 \leq n, m \leq 2 \times 10^52≤n,m≤2×105,0≤op≤10 \leq op \leq 10≤op≤1,1≤l≤r≤n1 \leq l \leq r \leq n1≤l≤r≤n,SSS 中只含字符 0 和字符 1。
C++实现
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,h,blk[N],fst[N],lst[N],tag[N],a[N],sum[N][2];
void read(int &x) {scanf("%d",&x);}
void write(int x) {printf("%d\n",x);}
void update(int l,int r){
int bl=blk[l],br=blk[r];
if (bl==br) {
for (int i=l;i<=r;i++) sum[bl][a[i]]--,a[i]^=1,sum[bl][a[i]]++;
return;
}
for (int i=bl+1;i<br;i++) tag[i]^=1;
for (int i=l;i<=lst[bl];i++) sum[bl][a[i]]--,a[i]^=1,sum[bl][a[i]]++;
for (int i=fst[br];i<=r;i++) sum[br][a[i]]--,a[i]^=1,sum[br][a[i]]++;
}
int query(int l,int r){
int bl=blk[l],br=blk[r],ans=0;
if (bl==br) {
for (int i=l;i<=r;i++) if (a[i]^tag[bl]==1) ans++;
return ans;
}
for (int i=bl+1;i<br;i++) ans+=sum[i][1^tag[i]];
for (int i=l;i<=lst[bl];i++) if (a[i]^tag[bl]==1) ans++;
for (int i=fst[br];i<=r;i++) if (a[i]^tag[br]==1) ans++;
return ans;
}
int main(){
read(n);read(m);
h=(int)sqrt(n);
for (int i=1;i<=n;i++) blk[i]=(i-1)/h+1;
for (int i=1;i<=n;i++)
if (blk[i]!=blk[i-1]) fst[blk[i]]=i,lst[blk[i-1]]=i-1;
lst[blk[n]]=n;
for (int i=1;i<=n;i++) {
char s=getchar();
while (s!='0'&&s!='1') s=getchar();
a[i]=s-'0';
sum[blk[i]][a[i]]++;
}
for (int i=1;i<=m;i++) {
int opt,l,r;
read(opt);read(l);read(r);
if (opt==0) update(l,r);
if (opt==1) write(query(l,r));
}
}

后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
用C++实现信奥题 P2574 XOR的艺术&spm=1001.2101.3001.5002&articleId=156445288&d=1&t=3&u=749e0c45d4f94aeba22d61be89423e23)

被折叠的 条评论
为什么被折叠?



