一道线段树分治模板题。


​https://www.luogu.com.cn/problem/P5787​

线段树分治用于解决在时间上插入的离线处理方法。具体将时间轴建立为一棵线段树,一个操作对时间轴的影响插入logn段线段树中,最后遍历线段树到时间路径上进行操作。相对于CDQ分治,此时询问被看做是一个时间点。

就挺棒的,该题就参照NOIP2010关押罪犯那么搞来判断二分图,每个点拆分为x和x+n(x与它的敌人),当x与y连边,则相当于x与y+N连边,y与x+n连边(敌人的敌人就是朋友),当然,如果x与x+n连边了则证明不是二分图。

实现上由于线段树的撤销操作,并查集不路径压缩,按秩合并即可。

#include<bits/stdc++.h>

using namespace std;
const int maxn = 2e5+5;
int n;
int a[maxn];
char ss[maxn];
int b[maxn],r[maxn];
int bl,rl;
void sol() {
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
bl = rl = 0;
scanf("%s",&ss[1]);
for(int i=1;i<=n;i++) {
if(ss[i]=='B') b[++bl] = a[i];
else r[++rl] = a[i];
}
sort(b+1,b+1+bl);
sort(r+1,r+1+rl,greater<int>());
bool flag = 1;
for(int i=1;i<=bl;i++) {
if(b[i]<i) flag = 0;
}
for(int i=1;i<=rl;i++) {
if(r[i]>(n-i+1)) flag = 0;
}
if(flag) puts("YES");
else puts("NO");
}

int main(){
int t;
cin>>t;
while(t--) sol();
return 0;
}