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;
}
posted @ 2026-01-17 21:42  XP3301_Pipi  阅读(1)  评论(0)    收藏  举报
Title