ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「StOI-1」IOI计数

2021-02-03 09:02:59  阅读:312  来源: 互联网

标签:io oi int mid 计数 StOI IOI now lx


[洛谷链接](https://www.luogu.com.cn/problem/P6373)

题目背景

蒻L_C_A想了解一下IOI,可他太菜了,看不懂题目,只会数数。

题目描述

给定一个长度为 nn 字符串 SS ,同时进行 mm 次操作:
操作1:11 xx cc 表示将第 xx 个字符改为 cc( cc 只会为 I 或 O )。
操作2:22 ll rr 询问字符串 SS 中有多少对三元组 (i,j,k) (i,j,k) 满足:
S_{i}=S i = I ,S_{j} = S j = O, S_{k} = S k = I
并且 l ≤ i < j < k ≤ rl ≤ i < j < k ≤ r 。

输入格式

输入第一行两个正整数 nn 和 mm 。
接下来一行是长度为 nn 的字符串 ss ,接下来 mm 行是操作。
含义均如题。

输出格式

输出若干行:对于所有操作2,输出查询的答案,要求每个答案之间换行。

输入输出样例

输入1

4 3
IOOI
2 1 4
1 1 O
2 1 2

输出1

2
0

输入2

10 10
IIOOIOIIIO
1 1 I
2 1 7
1 5 O
2 5 9
1 4 I
1 10 I
2 1 10
2 5 10
2 2 8
2 3 9

输出2

11
0
34
0
11
6

分析:根据在一个点修改I, O,在一个区间内查询IOI,可知这题是道单点修改,区间查询的题,但是IOI并不是一个单独的数据,可以有很多组合,所以我们应该统计每一种组合的数量,具体的:

(为组合后的结构体,x,y分别是左右两边的结构体)
z.i = x.i + y.i;
z.o = x.o + y.o;
z.io = x.io + y.io + x.i * y.o;
z.oi = x.oi + y.oi + x.o * y.i;
z.ioi = x.ioi + y.ioi + x.io * y.i + x.i * y.oi;
io,oi首先单独加上左右单独的数量,再加上左右组合的数量(乘法原理
IOI亦是同理,左右单独,再加上左右组合。

注意:再ask时一定不要,把左右的结构体赋给中间的,可能有一边没有访问(zz错误,还卡了0.5h)

#include<cstdio>
#define int long long

struct lx {
	int now, l, r;
	int i, o, oi, io, ioi;
}a[2000005];

char h[500005];

lx put(lx w, lx x, lx y) {
	lx z;
	z.l = w.l; z.r = w.r; z.now = w.now; //单独开的结构体注意要传now,l,r基本信息
	z.i = x.i + y.i;
	z.o = x.o + y.o;
	z.io = x.io + y.io + x.i * y.o;
	z.oi = x.oi + y.oi + x.o * y.i;
	z.ioi = x.ioi + y.ioi + x.io * y.i + x.i * y.oi;
	return z;
}

void build(int now, int l, int r) {
	a[now].l = l; a[now].r = r; 
//	printf("%d %d %d\n", now, l, r);
	if(l == r) return; int mid = (l + r) >> 1;
	build(now * 2, l, mid);
	build(now * 2 + 1, mid + 1, r);
}

void update(int now, int l, char s, bool flag) {
	lx x, y;
	if(a[now].l == a[now].r) {
		a[now].i = 0; a[now].o = 0;
		if(s == 'O') {
			a[now].o = 1; h[l] = 'O';
		} else if(s == 'I') {
			a[now].i = 1; h[l] = 'I';
		} return;
	} int mid = (a[now].l + a[now].r) >> 1;
	if(mid >= l) {
		update(now * 2, l, s, flag);
	} else {
		update(now * 2 + 1, l, s, flag);
	} a[now] = put(a[now], a[now * 2], a[now * 2 + 1]);
	return ;
}

lx ask(int now, int l, int r) {
	lx x, y;
	if(l <= a[now].l && a[now].r <= r) return a[now];
	x.i = 0; x.io = 0; x.oi = 0; x.o = 0; x.ioi = 0;
	y.i = 0; y.io = 0; y.oi = 0; y.o = 0; y.ioi = 0;
	int mid = (a[now].l + a[now].r) >> 1;
	if(mid >= l) {
		x = ask(now * 2, l, r);
	} if(mid < r) {
		y = ask(now * 2 + 1, l, r);
	} return put(a[now], x, y);//一定要直接传不要赋值
}

signed main() {
	char s[5];
	int n, m, c, l, r;
	scanf("%lld %lld", &n, &m);
	build(1, 1, n);//建树
	scanf("%s", h + 1);
	for(int i = 1; i <= n; i ++) { update(1, i, h[i], 1); } //我是单独再把原数组添加进树,可以在建树时加
	for(int i = 1; i <= m; i ++) {
		scanf("%lld", &c);
		if(c == 1) {
			scanf("%lld %s", &l, s);
			update(1, l, s[0], 0);
//			for(int i = 1; i <= n; i ++) {
//				printf("%c", h[i]);
//			} printf("\n");
		} else {
			scanf("%lld %lld", &l, &r);
			printf("%lld\n", ask(1, l, r).ioi);//因为传的结构体所以要加具体的变量
		}
	}
} 

标签:io,oi,int,mid,计数,StOI,IOI,now,lx
来源: https://www.cnblogs.com/lakafl/p/14365180.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有