目录
显示
题目链接
https://www.luogu.org/problem/P4979
题解
Part 1 线段树做法
用 \(1,2,3\) 分别代表原来的三种颜色,\(-1\) 代表该区间内有多种颜色。
修改操作就和普通的区间修改操作一样了。
而对于查询操作,我们先查查询区间内的颜色是否为单种颜色,再查区间两侧颜色是否不同。
代码这里略去。
Part 2 珂朵莉树做法
个人认为本题采用珂朵莉树来解决,理解和实现都相对于线段树容易不少。
当然,由于题目中没有明确提到数据随机,所以该做法事实上是可以卡的。(下面的代码在不开 -O2 优化的情况下并不能通过这道题)
查询操作暴力遍历所有区间,判断每个区间颜色是否相同即可。
一种看上去有用的优化是在查询的时候顺带合并颜色相同的区间,不过实测反而起到了负优化…(参见 R23465047,猜测可能是调用函数过多的原因)
#include <cstdio> #include <set> using namespace std; struct node { int l,r; mutable int val; node(int L=0,int R=-1,int Val=0) { l=L,r=R,val=Val; } bool operator<(const node&a)const { return l<a.l; } }; set<node> se; char s[500005]; int n,k; set<node>::iterator split(int pos) { auto it=se.lower_bound(node(pos)); if(it!=se.end()&&it->l==pos)return it; it--; int l=it->l,r=it->r,val=it->val; se.erase(it); se.insert(node(l,pos-1,val)); return se.insert(node(pos,r,val)).first; } void assign(int l,int r,int val) { auto itr=split(r+1),itl=split(l); se.erase(itl,itr); se.insert(node(l,r,val)); } bool query(int l,int r) { auto itr=split(r+1),itl=split(l); for(auto it=itl;it!=itr;it++) if(it->val!=itl->val)return false; if(l!=1&&r!=n) { itl--; return itl->val!=itr->val; } else return true; } int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++) se.insert(node(i,i,s[i]-'A')); scanf("%d",&k); while(k--) { scanf("%s",s); if(s[0]=='A') { int x,y; scanf("%d%d",&x,&y); scanf("%s",s); assign(x,y,s[0]-'A'); } else { int x,y; scanf("%d%d",&x,&y); puts(query(x,y)?"Yes":"No"); } } return 0; }