网址如下:
P3870 [TJOI2009] 开关 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
看C艹书看不下去,就到洛谷上随机抽一道题做
一道线段树的问题
实际上,关于线段树的知识是我现学的(我树的知识都不知道,乐)
总结来说,比较重要的就是“懒标记”,加上传值和读取以及构建树的相应操作
算法学习网址如下:
算法学习笔记(14): 线段树 - 知乎 (zhihu.com)
第一次用,有点不熟悉,在读取的时候忘记更新mark(懒标记)了,导致刚开始只有10分
代码如下:
#include
using namespace std;
void update(int l, int r, int p, int cl, int cr);
int query(int l, int r, int p, int cl, int cr);
int tree[100000000], mark[100000000];
int n, m;
int main(void)
{
//输入
scanf("%d%d", &n, &m);
//处理
for(int i = 0; i < m; i++)
{
int n_tmp, l, r;
scanf("%d%d%d", &n_tmp, &l, &r);
if(n_tmp)
printf("%d\n", query(l, r, 1, 1, n));
else
update(l, r, 1, 1, n);
}
return 0;
}
void update(int l, int r, int p, int cl, int cr)
{
if(cl > r || cr < l)
return;
if(cl >= l && cr <= r)
{
tree[p] = (cr - cl + 1) - tree[p];
mark[p] += 1;
}
else
{
int mid = (cl + cr) / 2;
mark[2 * p] += mark[p], mark[2 * p + 1] += mark[p];
if(mark[p] % 2)
{tree[2 * p] = (mid - cl + 1) - tree[2 * p], tree[2 * p + 1] = (cr - mid) - tree[2 * p + 1];}
mark[p] = 0;
update(l, r, 2 * p, cl, mid);
update(l, r, 2 * p + 1, mid + 1, cr);
tree[p] = tree[2 * p] + tree[2 * p + 1];
}
}
int query(int l, int r, int p, int cl, int cr)
{
if(cl > r || cr < l)
return 0;
if(cl >= l && cr <= r)
return tree[p];
else
{
int mid = (cl + cr) / 2;
mark[2 * p] += mark[p], mark[2 * p + 1] += mark[p];
if(mark[p] % 2)
{tree[2 * p] = (mid - cl + 1) - tree[2 * p], tree[2 * p + 1] = (cr - mid) - tree[2 * p + 1];}
mark[p] = 0;
return query(l, r, 2 * p, cl, mid) + query(l, r, p * 2 + 1, mid + 1, cr);
}
}
我在算法书上看到:因为C艹的流输入的效率相对较慢,所以在题目有大量输入的时候,不建议用这个
所以我换成了C风格的输入输出