AtCoder Beginner Contest 380 A - E

Zhang_Wenjie發表於2024-11-17

link

賽時是 ABC,D 一眼要找規律,跳了,E 題思路想了接近半個小時,然後發現假了,最後沒調出來,

問一下 dalao 發現其實很簡單維護。。。基礎線段樹沒切掉,哎呦

不過發現比賽打多了,理解速度和手速都有些提高,幸好前三題秒掉了,要不然 rating 又會是一坨


A - 123233

B - Hurdle Parsing

C - Move Segment

D - Strange Mirroring

一道簡單遞迴。

發現字串是成倍增長的,顯然考慮找規律,

手摸一下會發現,要找的字母其實是由之前的 相反的 字母轉換過來的,而這條轉換鏈也很有規律,

比如樣例 1,找 30 位置,理解為 2 ^ 5 - 2,是由 14(2 ^ 4 - 2)大小寫取反轉換,又由 6(2 ^ 3 - 2)...... 最後將規模轉化為原長字串中。

顯然遞迴是 \(\log\) 的,還有,每次找位置的規模是隨遞迴減小的,所以達不到 \(\log^2n\)

code
#include <bits/stdc++.h>
#define re register int 
#define int long long

using namespace std;
const int N = 2e5 + 10;

string s;
int q;

inline char change(char x)
{
	if ('a' <= x && x <= 'z') return x - 'a' + 'A';
	else return x - 'A' + 'a';
}

inline char find(int x, bool flag)
{
	if (x <= s.size())
	{
		if (flag) return change(s[x - 1]);
		else return s[x - 1];
	}
	int k = s.size();
	while ((k << 1ll) < x) k <<= 1ll;
	find(x - k, !flag);
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> s;
	cin >> q;
	while (q --)
	{
		int x; cin >> x;
		cout << find(x, false) << ' ';
	}
	cout << '\n';
	return 0;
}

E - 1D Bucket Tool

維護序列的全相等聯通塊,感覺是個很常見的東西,確實做法很多,set,dsu 都可以,

原諒我只想到複雜度更劣的 線段樹 + 二分 qwq

一眼看上去,是個很可以用線段樹維護的 ds 題

區間修改很簡單

主要是如何維護,給定一個位置,找該位置的顏色的最大連通塊,還要是 \(\log\) 級別的時間

一開始是想倍增跳,但是發現不好維護 連續相同

最後只能是從線段樹直接維護的角度想,突然注意到,找連通塊的左右界,是可以二分的。這是顯然的,可以簡單考慮為區間長度越長,越更可能 不連續相同,也就是說如果長度更短的區間都不能連續,那麼更長的不可能更優

然後考慮區間連續相同是不是等價於 \(\bigcap\limits_{i = l}^r a_i = a_k~(k\in[l, r])\) 呢?然後 wa 了一大堆。。。

賽後發現隨便舉出反例 10 & 11 & 10 = 10

其實是可以直接維護這個邏輯的,,,子區間相同或否,pushup 維護一個標誌值就可以了。最後區間查詢,發現資料範圍比較小,直接開個顏色的桶就可以了。

複雜度 \(O(n\log^2n)\)

code
#include <bits/stdc++.h>
#define re register int 
#define lp p * 2
#define rp p * 2 + 1
#define int long long

using namespace std;
typedef pair<int, int> PII;
const int N = 5e5 + 10;

struct Tree { int l, r, sum, tag, flag; } t[N << 2];
int n, q, num[N];

inline void push_up(int p)
{
	t[p].sum = t[lp].sum + t[rp].sum;
	t[p].flag = ((t[lp].flag == t[rp].flag && t[lp].flag) ? t[lp].flag : 0);
}

inline void push_down(int p)
{
	if (t[p].tag)
	{
		t[lp].sum = (t[lp].r - t[lp].l + 1) * t[p].tag;
		t[rp].sum = (t[rp].r - t[rp].l + 1) * t[p].tag;
		t[lp].flag = t[rp].flag = t[p].tag;
		t[lp].tag = t[p].tag;
		t[rp].tag = t[p].tag;
		t[p].tag = 0;
	}
}

inline void build(int p, int l, int r)
{
	t[p].l = l, t[p].r = r;
	if (l == r)
	{
		t[p].sum = t[p].flag = l;
		return;
	}
	int mid = (l + r) >> 1;
	build(lp, l, mid); build(rp, mid + 1, r);
	push_up(p);
}

inline void update(int p, int l, int r, int k)
{
	if (l <= t[p].l && t[p].r <= r)
	{
		t[p].sum = (t[p].r - t[p].l + 1) * k;
		t[p].flag = k;
		t[p].tag = k;
		return;
	}
	push_down(p);
	int mid = (t[p].l + t[p].r) >> 1;
	if (l <= mid) update(lp, l, r, k);
	if (r > mid) update(rp, l, r, k);
	push_up(p);
}

inline int query(int p, int l, int r)
{
	if (l <= t[p].l && t[p].r <= r) return t[p].sum;
	push_down(p);
	int res = 0;
	int mid = (t[p].l + t[p].r) >> 1;
	if (l <= mid) res += query(lp, l, r);
	if (r > mid) res += query(rp, l, r);
	
	return res;
}

inline bool ask(int p, int l, int r, int k)
{
	if (l <= t[p].l && t[p].r <= r)
	{
		if (t[p].flag != k) return false;
		return true;
	}
	push_down(p);
	bool res = true;
	int mid = (t[p].l + t[p].r) >> 1;
	if (l <= mid) res &= ask(lp, l, r, k);
	if (r >mid) res &= ask(rp, l, r, k);
	
	return res;
}

inline PII search(int x)
{
	int a = query(1, x, x);	
	int L, R;
	
	int l = 1, r = x;
	while (l < r)
	{
		int mid = (l + r) >> 1;
		if (ask(1, mid, x, a)) r = mid; 
		else l = mid + 1;
	}
	L = l;
	
	l = x, r = n;
	while (l < r)
	{
		int mid = (l + r + 1) >> 1;
		if (ask(1, x, mid, a)) l = mid;
		else r = mid - 1;
	}
	R = l;
	
	return {L, R};
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> n >> q;
	build(1, 1, n);	
	for (re i = 1; i <= n; i ++) num[i] = 1;
	
	while (q --)
	{
		int op, x, y; cin >> op;
		if (op == 1)
		{
			cin >> x >> y;
			PII k = search(x); int l = k.first, r = k.second;
			
			num[query(1, x, x)] -= (r - l + 1);
			update(1, l, r, y);	
			num[y] += (r - l + 1);
			
		}
		else 
		{
			cin >> x;
			cout << num[x] << '\n';
		}
	}
	
	return 0;
}

相關文章