赛时是 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\) 级别的时间
一开始是想倍增跳,但是发现不好维护 连续相同
最后只能是从线段树直接维护的角度想,突然注意到,找连通块的左右界,是可以二分的。这是显然的,可以简单考虑为区间长度越长,越更可能 不连续相同,也就是说如果长度更短的区间都不能连续,那么更长的不可能更优
然后考虑区间连续相同是不是等价于 \(\bigcup\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;
}