E. データ構造ファン (思考 + XOR プレフィックス合計)

問題 - E - コードフォース

整数配列 a1、a2、...、an、および n 文字で構成されるバイナリ文字列 † s が与えられます。

オーガスティンはデータ構造の愛好家です。したがって、彼は、q 個のクエリに応答できるデータ構造を実装するように求めています。ここには 2 種類のクエリがあります。

 
 

プレーンテキスト

 
 
"1 l r" (1≤l≤r≤n) — 将 l ≤ i ≤ r 的每个字符 si 替换为其相反值。也就是,将所有的 0 替换为 1,将所有的 1 替换为 0。
"2 g" (g∈{0,1}) — 计算所有满足 si=g 的索引 i 对应的数字 ai 的按位异或(bitwise XOR)值。注意,空集合的异或值被认为是等于 0。

オーガスティンがすべての質問に答えるのを手伝ってください。

たとえば、n=4、a=[1,2,3,6]、s=1001 の場合、次の一連のクエリを検討します。

 
 

プレーンテキスト

 
 
"2 0" — 我们对于满足 si=0 的索引 i 感兴趣,因为 s=1001,这些索引是 2 和 3,所以查询的答案将是 a2⊕a3=2⊕3=1。
"1 1 3" — 我们需要将字符 s1,s2,s3 替换为它们的相反值,所以在查询之前 s=1001,在查询之后:s=0111。
"2 1" — 我们对于满足 si=1 的索引 i 感兴趣,因为 s=0111,这些索引是 2, 3 和 4,所以查询的答案将是 a2⊕a3⊕a4=2⊕3⊕6=7。
"1 2 4" — s=0111 → s=0000。
"2 1" — s=0000,没有满足 si=1 的索引,所以由于空集合的异或值被认为是等于 0,这个查询的答案是 0。

† バイナリ文字列は、文字 0 または 1 のみを含む文字列です。

入力

入力の最初の行には、テスト ケースの数を表す整数 t (1≤t≤10^4) が含まれています。

次に各テストケースについて説明します。

各テスト ケースの説明の最初の行には、配列の長さである整数 n (1≤n≤10^5) が含まれています。

テスト ケースの 2 行目には、n 個の整数 a1、a2、...、an (1≤ai≤10^9) が含まれています。

テスト ケースの 3 行目には、長さ n のバイナリ文字列 s が含まれています。

テスト ケースの 4 行目には、クエリの数を表す整数 q (1≤q≤10^5) が含まれています。

テスト ケースの後続の q 行はクエリを記述します。各クエリの最初の数字 tp ∈ {1,2} は、クエリのタイプを示します。 tp=1 の場合、その後に 2 つの整数 1≤l≤r≤n が続き、パラメータ l,r を使用する必要があることを示します。タイプ 1 の演算を実行します。tp=2 の場合、整数 g∈{0,1} が続き、パラメータ g を使用してタイプ 2 の演算を実行する必要があることを示します。

すべてのテスト ケースの n の合計が 10^5 を超えず、q の合計が 10^5 を超えないことを確認してください。

出力

各テスト ケースのタイプ 2 クエリごとに、対応するクエリに対する回答を出力します。

入力

5 5 1 2 3 4 5 01000 7 2 0 2 1 1 2 4 2 0 2 1 1 1 3 2 1 6 12 12 14 14 5 5 001001 3 2 1 1 2 4 2 1 4 7 7 7 777 1111 3 2 0 1 2 3 2 0 2 1000000000 996179179 11 1 2 1 5 1 42 20 47 7 00011 5 1 3 4 1 1 1 1 3 4 1 2 4 2 0

出力

3 2 6 7 7 11 7 0 0 16430827 47

知らせ

最初のテスト ケースを分析してみましょう。

"2 0" — si=0 のようなインデックス i の場合、これらのクエリに対する答えが a1⊕a3⊕a4⊕a5=1⊕3⊕4⊕5=3 になるという事実に興味があります。"2 1" — si=1 のようなインデックス i の場合、これらのクエリに対する答えが a2=2 になるという事実に興味があります。"1 2 4" — 文字 s2、s3、s4 を反対の値に置き換える必要があります。つまり、クエリの前は s=01000、クエリの後は s=00110 になります。"2 0" — si=0 のようなインデックス i の場合、これらのクエリに対する答えが a1⊕a2⊕a5=1⊕2⊕5=6 になるという事実に興味があります。"2 1" — si=1 のようなインデックス i について、これらのクエリに対する答えが a3⊕a4=3⊕4=7 になるという事実に興味があります。「1 1 3」 — s=00110 → s=11010。"2 1" — si=1 のようなインデックス i の場合、これらのクエリに対する答えが a1⊕a2⊕a4=1⊕2⊕4=7 になるという事実に興味があります。

解決策:
最初は間隔の変更を見て、どのようなデータ構造を使用するかを考えていましたが、最終的にはわかりませんでした。

ゲームの後、他の人のコードを見て、それが思考的な質問であることがわかりました。

XOR プレフィックスの合計を記録する必要があるだけです。これは、最初は位置 0 の XOR 合計と位置 1 の XOR 合計です。

間隔を変更したい場合は、XOR プレフィックス合計に基づいて、その間隔の XOR 合計 t をすぐに見つけることができます。

s0 ^= t

s1 ^= t

なぜこれで大丈夫なのでしょうか?

例として 1 を考えてみましょう。t には、現時点では 0、現時点では 1 である XOR 合計が存在する可能性があります。それらは以前に計算したため、一時的な XOR 合計です。それらをもう一度 XOR すると、前の XOR 合計は次のようになります。 XORは無い、XORは一気にちょうど良い、この処理は逆転処理ではないでしょうか?

0と同じ

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> PII;
int a[100050];
int pre[100054];
void solve()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
	}
	string s;
	cin >> s;
	vector<int> ans(10);
	s = "?" + s;
	for(int i = 1;i <= n ;i++)
	{
		ans[s[i] - '0'] ^= a[i];
		pre[i] = pre[i - 1]^a[i];
	}
	int q;
	cin >> q;
	while(q--)
	{
		int op,l,r;
		cin >> op >> l;
		if(op == 2)
		{
			cout << ans[l] <<" ";
		}
		else
		{
			cin >> r;
			int t = pre[r]^pre[l - 1];
			ans[0] ^= t;
			ans[1] ^= t;
		}
	}
	cout <<"\n";
} 
signed main()
{
	int t = 1;
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t ;	
	while(t--)
	{
		solve();
	}
}

おすすめ

転載: blog.csdn.net/m0_64158084/article/details/132752346