链接: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+97if (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;
}