CF763E Timofey and our friends animals

祭我调了一天的莫队,1s的时限还是过不了,能卡的自己卡吧。

这道题莫队太粪了,考虑每个都是 \([L,R]\) 的询问,所以我们一定可以用莫队写。

因为查询联通块只能用并查集维护。

但是很遗憾不能删边。

这下就只能使用回滚莫队了。

枚举每一个块,从右段点开始。

如果一次询问在同一个块内,我们并不能将右指针闪边,只能暴力处理,块长 \(\sqrt{n}\) ,所以单次操作 \(O(\sqrt{n})\)

对于横跨多个块的询问,容易发现右端点递增,左端点每次仍暴力处理。

左端点依然块内 \(O(\sqrt{n})\) ,右端点拓展平摊 \(\sqrt{n}\) 次,最长拓展 \(n\) 的长度,平均每次 \(O(n/\sqrt{n}) = O(\sqrt{n})\)

但拓展时需要可撤销并查集,按秩合并, \(O(logn)\)

于是总复杂度 \(O(n\sqrt{n}logn)\)

完了。

\(\huge \mathscr{Code}:\)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
int n,k,m,q,fa[N],pos[N],ans[N],posR[N],cres,recR,siz[N];
stack<pair<int,int>> stk;
vector<int> g[N],gg[N];
struct node{
	int l,r,id;
	inline friend bool operator<(node a,node b){
		if(pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l];
		return a.r<b.r;
	}
}qs[N];
int find(const int x){
	if(fa[x]==x) return x;
	return find(fa[x]);
}
int add(const int x,const int lim,const bool tag){
	cres++;
	int ans = 0,fx = find(x); 
	for(int y:tag?g[x]:gg[x]){
		if(tag?y<=lim:y>=lim){
			int fy = find(y);
			if(fx!=fy){
				ans++;
				stk.push({fx,fy});
				if(siz[fy]<siz[fx]) swap(fx,fy);
				siz[fy] += siz[fx];
				fa[fx] = fy;
				fx = find(x);
			}
		}
	}
	cres -= ans;
	return ans;
}
void del(int end){
	while(end--){
		fa[stk.top().first] = stk.top().first;
		siz[stk.top().second] -= siz[stk.top().first];
		stk.pop();
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	freopen("unicom.in","r",stdin);
	freopen("unicom.out","w",stdout);
	cin>>n>>k>>m;
	int block = sqrt(n);
	for(int i=1;i<=n;i++){
		fa[i] = i;
		pos[i] = (i-1)/block + 1;
		posR[pos[i]] = i;
	}
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		if(x>y) swap(x,y);
		g[x].emplace_back(y),gg[y].emplace_back(x);
	}
	cin>>q;
	for(int i=1;i<=q;i++){
		cin>>qs[i].l>>qs[i].r;
		qs[i].id = i;
	}
	sort(qs+1,qs+q+1);
	//pre-process above,violent DS below 
	for(int i=1;i<=q;i++){
		int base = posR[pos[qs[i].l]];
		if(pos[qs[i].l]!=pos[qs[i-1].l] or (pos[qs[i-1].l]==pos[qs[i-1].r] && pos[qs[i].l]!=pos[qs[i].r])){
			del(stk.size());
			cres = 0;
			recR = base;
		}
		if(pos[qs[i].l]==pos[qs[i].r]){
			cres = 0;
			for(int j=qs[i].l;j<=qs[i].r;j++) add(j,qs[i].l,0);
			ans[qs[i].id] = cres;
			del(stk.size());
		}
		else{
			for(int j=recR+1;j<=qs[i].r;j++) add(j,base+1,0); 
			recR = qs[i].r;
			int tmp = cres,cnttop = 0;
			for(int j=base;j>=qs[i].l;j--) cnttop += add(j,recR,1);
			ans[qs[i].id] = cres;
			del(cnttop);
			cres = tmp;
		}
	}
	for(int i=1;i<=q;i++) cout<<ans[i]<<'\n';
	return 0;
}
posted @ 2025-07-10 19:59  OrangeRED  阅读(11)  评论(0)    收藏  举报