MnZn求助!!
查看原帖
MnZn求助!!
519384
Link_Cut_Y楼主2022/4/4 12:40

看到的大佬帮忙看看吧QAQ求求了

写了两个版本,样例都不过(主要是输出都错在同样的地方)

递归版:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 20000010;

int n, m, idx, w[N], lastans;
struct Tree
{
	int s[2]; // 表示左右儿子的 idx 
	int add, sum, size;
	
	#define ls tr[u].s[0]
	#define rs tr[u].s[1]
}tr[N];

void pushup(int u)
{
	tr[u].size = tr[ls].size + tr[rs].size + 1;
	tr[u].sum += tr[ls].sum + tr[rs].sum;
}

void pushdown(int u)
{
	if (tr[u].add)
	{
		tr[ls].add += tr[u].add;
		tr[rs].add += tr[u].add;
		tr[ls].sum += tr[ls].size * tr[u].add;
		tr[rs].sum += tr[rs].size * tr[u].add;
		tr[u].add = 0;
	}
}

void insert(int u, int x, int v)
{
	if (!x)
	{
		tr[u].sum = v, tr[u].size = 1;
		return;
	}
	
	int az = x & 1;
	if (!tr[u].s[az]) tr[u].s[az] = ++ idx;
	insert(tr[u].s[az], x >> 1, v);
	pushup(u);
}

void build(int n)
{
	for (int i = 1; i <= n; i ++ )
		insert(0, i, w[i]);
}

void modify(int u, int c, int v)
{
	if (!c)
	{
		tr[u].add += v, tr[u].sum += tr[u].size * v;
		return;
	}
	
	pushdown(u);
	int az = c & 1;
	modify(tr[u].s[az], c >> 1, v);
	pushup(u);
}

int query(int u, int c)
{
	if (!c) return tr[u].sum;
	
	pushdown(u);
	int az = c & 1;
	return query(tr[u].s[az], c >> 1);
}

int main()
{
	scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= n; i ++ )
		scanf("%d", &w[i]);
		
	build(n);
	
	while (m -- )
	{
		int op, x, y, v;
		scanf("%d", &op);
		op = (op + lastans) % 2 + 1;
		
		if (op == 1)
		{
			scanf("%d%d%d", &x, &y, &v);
			modify(0, y % (1 << x), v);
		}
		
		else
		{
			scanf("%d%d", &x, &y);
			printf("%d\n", lastans = query(0, y % (1 << x)));
		}
	}
	
	return 0;
}

迭代版

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 200010;

int n, m, idx, w[N], lastans;
struct Tree
{
	int s[2]; // 表示左右儿子的 idx 
	int add, sum, size;
	
	#define ls tr[u].s[0]
	#define rs tr[u].s[1]
}tr[N];

void pushup(int u)
{
	tr[u].size = tr[ls].size + tr[rs].size + 1;
	tr[u].sum += tr[ls].sum + tr[rs].sum;
}

void pushdown(int u)
{
	if (tr[u].add)
	{
		tr[ls].add += tr[u].add;
		tr[rs].add += tr[u].add;
		tr[ls].sum += tr[ls].size * tr[u].add;
		tr[rs].sum += tr[rs].size * tr[u].add;
		tr[u].add = 0;
	}
}

void insert(int x)
{
	int p = 0, u = x;
	while (x)
	{
		int v = x & 1;
		if (!tr[p].s[v]) tr[p].s[v] = ++ idx;
		p = tr[p].s[v]; 
		x >>= 1;
	}
	
	tr[p].sum = w[u], tr[p].size = 1;
	pushup(p);
}

void build(int n)
{
	for (int i = 1; i <= n; i ++ )
		insert(i);
}

void modify(int c, int v) // 将二进制后缀为 c 的子树增加 v 
{
	int p = 0;
	while (c)
	{
		pushdown(p);
		int v = c & 1;
		if (!tr[p].s[v]) return;
		p = tr[p].s[v];
		c >>= 1;
	}
	
	// 现在需要将 p 的子树增加 v 
	tr[p].add += v, tr[p].sum += tr[p].size * v;
	pushup(p);
}

int query(int c) // 求二进制后缀为 c 的子树和 
{
	int p = 0;
	while (c)
	{
		pushdown(p);
		int v = c & 1;
		if (!tr[p].s[v]) return 0;
		p = tr[p].s[v];
		c >>= 1;
	}
	
	return tr[p].sum;
}

int main()
{
	scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= n; i ++ )
		scanf("%d", &w[i]);
		
	build(n);
	
	while (m -- )
	{
		int op, x, y, v;
		scanf("%d", &op);
		op = (op + lastans) % 2 + 1;
		
		if (op == 1)
		{
			scanf("%d%d%d", &x, &y, &v);
			modify(y % (1 << x), v);
		}
		
		else
		{
			scanf("%d%d", &x, &y);
			printf("%d\n", lastans = query(y % (1 << x)));
		}
	}
	
	return 0;
}
2022/4/4 12:40
加载中...