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;
}

浙公网安备 33010602011771号