20260117 省选模拟赛
20260117 省选模拟赛
https://htoj.com.cn/cpp/oj/contest/detail?cid=22635323962240
Problem A. 染色
神秘性质。
从小的向大的染色需要考虑后面很多东西,不好做。所以反过来,从大向小做。
假设要将 \(S\) 染为红色,那么 枚举子集 \(T\) 作为蓝色子集的并集。此时 \(T\) 一定是蓝色,\(Z\subseteq S\land Z\not\subseteq T\) 的 \(Z\) 都是红色。\(T\) 构成子问题,\(O(3^n)\) dp 即可。
枚举子集太费时间,考虑怎么一次缩一个点。\(S\) 内一定有一个 \(x\),使得 \(x\in Z\subseteq S\) 的 \(Z\) 都是红色,否则所有蓝色集合的并就是 \(S\) 了。枚举这个 \(x\),即可 \(O(2^nn)\)。
Problem B. 信号过滤
如果只有一个滤波器,考虑维护被屏蔽的集合 \(S\),每次通带扩展时暴力删除,查询时在树状数组上查即可。
有多个滤波器,总势能达到 \(O(nq)\),不能直接做。
根号分治,设阈值 \(B\)。若这个滤波器有 \(>B\) 个操作,那么沿用上面的做法。维护集合时改为 ODT 维护通带,插入新通带时找出新增的位置。此时有 \(O(\frac{nq}{B})\) 次插入,\(O(q)\) 次查询,需要用 \(O(1)-O(\sqrt{n})\) 的分块平衡。
若这个滤波器有 \(\le B\) 次操作,那么 通带连续段不超过 \(B\) 个。维护通带连续段,每次查询时枚举每个连续段,是个二维偏序的形式。有 \(O(n)\) 次修改,\(O(qB)\) 次查询,需要 \(O(\sqrt{n})-O(1)\) 分块平衡。直接离线所有询问空间炸了,但 不同的连续段总共只有 \(O(q)\) 个,所以扫值域维,维护序列维,只离线这些区间即可。
总复杂度 \(O(n\sqrt{n})\)。
int n,Q,m,a[N];
int c[N],K;
int ans[N];
namespace Subtask1{
set<int> s;
int tr[N];
vector<int> vec[N];
void Update(int x,int v){
for(;x<=n;x+=x&-x) tr[x]+=v;
}
int Ask(int x){
int res=0;
for(;x;x-=x&-x) res+=tr[x];
return res;
}
void Solve(){
for(int i=1;i<=K;i++) s.emplace_hint(end(s),i);
for(int i=1;i<=n;i++) vec[a[i]].push_back(i);
while(Q--){
int op; read(op);
if(op==1){
int l,r,k;
read(l),read(r),read(k);
l=lower_bound(c+1,c+K+1,l)-c;
r=upper_bound(c+1,c+K+1,r)-c-1;
if(l>r) continue;
auto it=s.lower_bound(l);
while(it!=s.end()&&*it<=r){
for(int p:vec[*it]) Update(p,1);
it=s.erase(it);
}
}
else{
int l,r,k;
read(l),read(r),read(k);
printf("%d\n",Ask(r)-Ask(l-1));
}
}
}
}
const int B=550,D=M/B;
namespace Subtask2{
bool out[M];
vector<int> vec[M];
struct Query{
int op,l,r,k,id;
bool operator < (const Query& tmp)const{
return k<tmp.k||(k==tmp.k&&id<tmp.id);
}
}qy[M];
namespace Small{
int L[D+5],R[D+5],bl[M],C,s1[M],s2[D+5];
void Update(int x,int v){
for(int i=x;i<=R[bl[x]];i++) s1[i]+=v;
for(int i=bl[x];i<=C;i++) s2[i]+=v;
}
int Ask(int x){
return s1[x]+s2[bl[x]-1];
}
int Ask(int l,int r){
return Ask(r)-Ask(l-1);
}
struct Node{
int l,r,v;
};
vector<Node> q[M];
struct Line{
int l,r;
bool operator < (const Line& tmp)const{
return l<tmp.l||(l==tmp.l&&r<tmp.r);
}
};
set<Line> s;
map<Line,int> mp;
void Add(int l,int r,int t){
q[l-1].push_back(Node{mp[{l,r}],t,-1});
q[r].push_back(Node{mp[{l,r}],t,1});
}
void Insert(int l,int r,int t){
auto it=s.lower_bound({l,-IINF});
if(it!=s.begin()&&prev(it)->r>=l-1){
if(prev(it)->r>=r) return;
Add(prev(it)->l,prev(it)->r,t-1);
l=prev(it)->l;
it=s.erase(prev(it));
}
while(it!=s.end()&&it->r<=r){
Add(it->l,it->r,t-1);
it=s.erase(it);
}
if(it!=s.end()&&it->l<=r+1){
Add(it->l,it->r,t-1);
r=it->r,s.erase(it);
}
s.insert({l,r}); mp[{l,r}]=t;
}
void Solve(int ql,int qr){
s.clear(),mp.clear();
for(int i=ql;i<=qr;i++){
if(qy[i].op==2) continue;
qy[i].l=lower_bound(c+1,c+K+1,qy[i].l)-c;
qy[i].r=upper_bound(c+1,c+K+1,qy[i].r)-c-1;
if(qy[i].l>qy[i].r) continue;
Insert(qy[i].l,qy[i].r,i);
}
for(Line i:s) Add(i.l,i.r,qr);
}
void SolveAll(){
for(int i=1;i<=n;i+=B){
++C; L[C]=i,R[C]=min(i+B-1,n);
for(int j=L[C];j<=R[C];j++) bl[j]=C;
}
for(int i=1;i<=K;i++){
for(int j:vec[i]) Update(j,1);
for(Node j:q[i]){
for(int k=j.l;k<=j.r;k++)
if(qy[k].op==2){
ans[qy[k].id]+=j.v*Ask(qy[k].l,qy[k].r);
}
}
}
}
}
namespace Big{
struct Line{
int l,r;
bool operator < (const Line& tmp)const{
return l<tmp.l||(l==tmp.l&&r<tmp.r);
}
};
set<Line> s;
int L[D+5],R[D+5],bl[M],C,s1[M],s2[M];
void Clear(){
for(int i=1;i<=n;i++) s1[i]=s2[i]=0;
s.clear();
}
void Build(){
for(int i=1;i<=n;i+=B){
++C; L[C]=i,R[C]=min(n,i+B-1);
for(int j=L[C];j<=R[C];j++) bl[j]=C;
}
}
void Update(int x,int v){
s1[x]+=v;
s2[bl[x]]+=v;
}
int Ask(int l,int r){
int p=bl[l],q=bl[r],res=0;
if(p==q){
for(int i=l;i<=r;i++) res+=s1[i];
return res;
}
for(int i=l;i<=R[p];i++) res+=s1[i];
for(int i=L[q];i<=r;i++) res+=s1[i];
for(int i=p+1;i<=q-1;i++) res+=s2[i];
return res;
}
void Perform(int l,int r){
for(int i=l;i<=r;i++){
for(int j:vec[i])
Update(j,1);
}
}
void Insert(int l,int r){
auto it=s.lower_bound({l,-IINF});
int lst=l;
if(it!=s.begin()&&prev(it)->r>=l-1){
if(prev(it)->r>=r) return;
l=prev(it)->l;
lst=prev(it)->r+1;
it=s.erase(prev(it));
}
while(it!=s.end()&&it->r<=r){
Perform(lst,it->l-1);
lst=it->r+1; it=s.erase(it);
}
if(it!=s.end()&&it->l<=r+1){
Perform(lst,it->l-1);
r=it->r; s.erase(it);
}
else Perform(lst,r);
s.insert({l,r});
}
void Solve(int ql,int qr){
Clear();
for(int i=ql;i<=qr;i++){
if(qy[i].op==1){
qy[i].l=lower_bound(c+1,c+K+1,qy[i].l)-c;
qy[i].r=upper_bound(c+1,c+K+1,qy[i].r)-c-1;
if(qy[i].l<=qy[i].r) Insert(qy[i].l,qy[i].r);
}
else ans[qy[i].id]=Ask(qy[i].l,qy[i].r);
}
}
}
void Solve(){
for(int i=1;i<=n;i++) vec[a[i]].push_back(i);
for(int i=1;i<=Q;i++){
read(qy[i].op),read(qy[i].l),read(qy[i].r),read(qy[i].k);
qy[i].id=i;
if(qy[i].op==2) out[i]=1;
}
sort(qy+1,qy+Q+1);
Big::Build();
for(int i=1;i<=Q;){
int j=i;
while(j<Q&&qy[i].k==qy[j+1].k) ++j;
if(j-i+1<=B) Small::Solve(i,j);
else Big::Solve(i,j);
i=j+1;
}
Small::SolveAll();
for(int i=1;i<=Q;i++)
if(out[i]) printf("%d\n",ans[i]);
}
}
signed main(){
FileIO();
read(n),read(Q),read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) c[i]=a[i];
sort(c+1,c+n+1);
K=unique(c+1,c+n+1)-c-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(c+1,c+K+1,a[i])-c;
}
if(m==1) Subtask1::Solve();
else Subtask2::Solve();
return 0;
}

浙公网安备 33010602011771号