Educational Codeforces Round 102(Div。2の評価)D(Thinking&Line Segment Tree)

nn個の命令で構成されるプログラムが与えられます。最初に、単一の変数xxが00に割り当てられます。その後、命令には2つのタイプがあります。

  • xxを11増やします。
  • xxを11減らします。

 

次の形式のmmクエリが提供されます。

  • query ll rr — ll番目の命令とrr番目の命令の間のすべての命令が無視され、残りが順序を変更せずに実行された場合、xxはいくつの異なる値に割り当てられますか?

 

入力

最初の行には、単一の整数tt(1≤t≤10001≤t≤1000)—テストケースの数が含まれています。

次に、ttテストケースの説明が続きます。

各テストケースの最初の行には、2つの整数nnとmm(1≤n、m≤2⋅1051≤n、m≤2⋅105)が含まれています—プログラム内の命令の数とクエリの数です。

各テストケースの2行目には、プログラム(nn文字の文字列)が含まれています。各文字は「+」または「-」のいずれかであり、それぞれインクリメント命令とデクリメント命令です。

次のmm行のそれぞれには、2つの整数llとrr(1≤l≤r≤n1≤l≤r≤n)—クエリの説明が含まれています。

すべてのテストケースのnnの合計は、2⋅1052⋅105を超えません。すべてのテストケースのmmの合計は、2⋅1052⋅105を超えません。

出力

テストケースごとにmm整数を出力—クエリllごとに、rrは、ll番目の命令とrr番目の命令の間のすべての命令が無視され、残りが変更されずに実行される場合に、変数xxが割り当てられる個別の値の数を出力します。オーダー。

入力

コピー

2
8 4
-+--+--+
1 8
2 8
2 5
1 1
4 10
+-++
1 1
1 2
2 2
1 3
2 3
3 3
1 4
2 4
3 4
4 4

出力

コピー

1
2
4
4
3
3
4
2
3
2
1
2
2
2

注意

最初のテストケースの各クエリに残っている手順は次のとおりです。

  1. 空のプログラム—xxは00にしか等しくありませんでした。
  2. "-" —xxの値は00と-1-1でした。
  3. "--- +" — xxの値は00、-1-1、-2-2、-3-3、-2-2 —44個の異なる値があります。
  4. "+-+-+" —個別の値は11、00、-1-1、-2-2です。

 

本旨:

あなたに数xを与えてください、n個の操作があります、各操作はx + 1またはx-1を作ることができます、q回尋ねます、あなたが[l、r]の操作を削除するかどうか尋ねられるたびに、xはいくつの数になることができますか? 。

解決:

maxをプロセス中にxがなり得る最大値、minをプロセス中にxがなり得る最小値とします。答えはmax-min +1です。

クエリがない場合は、プレフィックス合計で最大値または最小値を実現できます。連続間隔を削除すると、それによってもたらされた寄与がカウントされます。

削除された間隔を[L、R]とすると、ラインセグメントツリーからL前の最大値/最小値とR後の最大値/最小値を取得できます。違いは[LからR後の最大値/最小値を差し引くことです。 、R]の寄与は、間隔の合計が削除後の真の最大/最小値であるということです。

受け入れられたコード

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

int mx[N * 4], mi[N * 4];
int pre[N], n, m;
char s[N];

#define ls (o << 1)
#define rs (ls | 1)
void Build(int o, int L, int R) {
	if (L == R) 
		mx[o] = mi[o] = pre[L];
	else {
		int mid = (L + R) >> 1;
		Build(ls, L, mid), Build(rs, mid + 1, R);
		mx[o] = max(mx[ls], mx[rs]);
		mi[o] = min(mi[ls], mi[rs]);
	}
}
int Ask_Mx(int o, int L, int R, int l, int r) {
	if (L >= l && R <= r)
		return mx[o];
	else {
		int mid = (L + R) >> 1, ans = -INF;
		if (mid >= l)
			Max(ans, Ask_Mx(ls, L, mid, l, r));
		if (mid < r)
			Max(ans, Ask_Mx(rs, mid + 1, R, l, r));
		return ans;
	}
}
int Ask_Mi(int o, int L, int R, int l, int r) {
	if (L >= l && R <= r)
		return mi[o];
	else {
		int mid = (L + R) >> 1, ans = INF;
		if (mid >= l)
			Min(ans, Ask_Mi(ls, L, mid, l, r));
		if (mid < r)
			Min(ans, Ask_Mi(rs, mid + 1, R, l, r));
		return ans;
	}
}

int main()
{
#ifdef OlaMins
	freopen("D:/input.txt", "r", stdin);
	//freopen("D:/output.txt", "w", stdout);
#endif

	int T; cin >> T;
	while (T--) {
		sc("%d %d %s", &n, &m, s + 1);
		for (int i = 1; i <= n; i++) 
			pre[i] = pre[i - 1] + (s[i] == '+' ? 1 : -1);  // 前缀和
		Build(1, 1, n);

		while (m--) {
			int l, r, mx1 = 0, mi1 = 0;
			sc("%d %d", &l, &r);

			if (l > 1) {
				Max(mx1, Ask_Mx(1, 1, n, 1, l - 1));   // L之前的答案可以直接得到
				Min(mi1, Ask_Mi(1, 1, n, 1, l - 1));
			}
			if (r < n) {    // R之后的答案要减去区间LR的贡献
				Max(mx1, Ask_Mx(1, 1, n, r + 1, n) - pre[r] + pre[l - 1]);
				Min(mi1, Ask_Mi(1, 1, n, r + 1, n) - pre[r] + pre[l - 1]);
			}

			printf("%d\n", mx1 - mi1 + 1);
		}
	}
	return 0; // 改数组大小!!!用pair改宏定义!!!
}

 

おすすめ

転載: blog.csdn.net/weixin_43851525/article/details/112981850