P8796 [蓝桥杯 2022 国 AC] 替换字符
链接:https://www.luogu.com.cn/problem/P8796
题目大意:
给出原字符串,给出修改区间,每步把区间中的a字符变为b字符。求最后的字符串是什么样子的。
思路:
很显然是线段树:区间修改。然后给每个添加上26容量的数组,代替键值对的作用。接着套模板就行。
注意的思路:先后区别,同一字符多次修改。实际上就是直接修改当前目标字符就行,然后必须往下传递。
但是不能AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
#define int long long
const int N = 1e5 + 10;
const int INF = -1;
int tag[N << 2][26];
int rf[26];
string s;
int n;
int ls(int p) { return p << 1; }
int rs(int p) { return p << 1 | 1; }
void addtag(int p, int pl, int pr, int from,int to)
{
//改,加上tag的作用
//for (int i = 0; i < 26; i++)rf[i] = tag[p][i];
for (int i = 0; i < 26; i++)
{
if (tag[p][i] == from)tag[p][i] = to;
}
if (tag[p][from - 'a'] == INF)tag[p][from - 'a'] = to;
}
//顺应上到下的先后顺序
void addtagMore(int p, int pl, int pr, int*to)
{
memset(rf, INF, sizeof(rf));
for (int i = 0; i < 26; i++)rf[i] = tag[p][i];
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 26; j++)
if (rf[i] == j+'a' and to[j]!=INF)
tag[p][i] = to[j];//i+97
if (rf[i] == INF)tag[p][i] = to[i];
}
}
void push_down(int p, int pl, int pr)
{
int mid = (pl + pr) >> 1;
addtagMore(ls(p), pl, mid, tag[p]);
addtagMore(rs(p), mid + 1, pr, tag[p]);
memset(tag[p], INF, sizeof(tag[p]));
}
void update(int L, int R, int p, int pl, int pr, int from,int to)
{
if (L <= pl and pr <= R)
{
addtag(p, pl, pr, from,to);
return;
}
push_down(p, pl, pr);
int mid = (pl + pr) >> 1;
if (L <= mid)update(L, R, ls(p), pl, mid, from,to);
if (R > mid)update(L, R, rs(p), mid + 1, pr, from,to);
}
void query(int p, int pl, int pr)
{
if (pl == pr)
{
if (tag[p][s[pl-1] - 'a']!=INF)cout<< (char)tag[p][s[pl-1] - 'a'];
else cout<<s[pl-1];
return;
}
push_down(p, pl, pr);
string res;
int mid = (pl + pr) / 2;
if (pl <= mid)query(ls(p), pl, mid);
if (pr > mid) query(rs(p), mid + 1, pr);
}
signed main()
{
IOS;
memset(tag, INF, sizeof(tag));
cin >> s; n = s.length();
int times; cin >> times;
for (int i = 0; i < times; i++)
{
int a, b; char c, d; cin >> a >> b >> c >> d;
update(a, b, 1, 1, n, c, d);
}
query( 1, 1, n);
return 0;
}
这种就是纯按照模板写的,可能是函数调用的过程增加了时间开销。所以参考题解区的核心代码:
for (int i = 0; i < 26; i++)
{
tag[ls(p)][i] = tag[p][tag[ls(p)][i]];//类似于f(f(x))键值对查找的方法
tag[rs(p)][i] = tag[p][tag[rs(p)][i]];
}
这样写就很巧妙。
所以AC代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
#define int long long
const int N = 1e5 + 10;
int tag[N << 2][26];
string s;
int n;
int ls(int p) { return p << 1; }
int rs(int p) { return p << 1 | 1; }
void init()
{
for (int i = 0; i < N << 2; i++)
for (int j = 0; j < 26; j++)
tag[i][j] = j;
}
void update(int p, int pl, int pr, int L, int R, int from, int to)
{
if (L<=pl and pr<=R)
{
for (int i = 0; i < 26; i++)
if (tag[p][i] == from)
tag[p][i] = to;
return;
}
int mid = (pl + pr) / 2;
for (int i = 0; i < 26; i++)
{
tag[ls(p)][i] = tag[p][tag[ls(p)][i]];//类似于f(f(x))键值对查找的方法
tag[rs(p)][i] = tag[p][tag[rs(p)][i]];
}
for (int i = 0; i < 26; i++)tag[p][i] = i;
if(L<=mid)update(ls(p), pl, mid, L, R, from, to);
if(R>mid)update(rs(p), mid + 1, pr, L, R, from, to);
}
void query(int p, int pl, int pr)
{
if (pl == pr)
{
char ans = tag[p][s[pl] - 97] + 'a';
cout << ans;
return;
}
for (int i = 0; i < 26; i++)
{
tag[ls(p)][i] = tag[p][tag[ls(p)][i]];//类似于f(f(x))键值对查找的方法
tag[rs(p)][i] = tag[p][tag[rs(p)][i]];
}
for (int i = 0; i < 26; i++)tag[p][i] = i;
int mid = (pl + pr) / 2;
query(ls(p), pl, mid);
query(rs(p), mid+1, pr);
}
signed main()
{
IOS;
init();
cin >> s; s = "0" + s;
int times;
n = s.length()-1;
cin >> times;
for (int i = 0; i < times; i++)
{
int a, b;char c, d; cin >> a >> b >> c >> d;
update(1, 1, n, a, b, c - 97, d - 97);
}
query(1, 1, n);
return 0;
}