CF687D

来个抽象点的做法。

首先显然可以将条件转化成,将 [l,r][l,r] 中的边从大到小加入一个图中,找出加入哪条边后不是一个二分图。显然可以用一个拓展域并查集维护。

观察到朴素暴力是 O(nm)=O(n3)O(nm)=O(n^3),几乎已经能过了(其实就是能过)。于是考虑进行一些小的处理,把它变成实际上就是能过的。

再观察,发现 n=1000n=1000 也是相对小的,考虑利用这个性质,nn 小说明可能可以 O(n)O(n) 合并两个并查集,于是尝试预处理一些并查集再合并。

因为每次肯定是从大往小加边,于是考虑先按照边权从小到大排序。发现大概 105q10^5q 次操作是可以接受的,所以值域上每 10510^5 分一块。

对于每一块内,我们想要快速判断,当前的并查集再并上这个区间内的所有编号 [l,r]\in[l,r] 的边后,是否还满足是一个二分图。

于是考虑对每一块开一棵线段树,线段树上每个节点都是一个并查集,存储编号区间 l,rl,r 且边权属于这个块内的所有边加入一个并查集的结果。

对于每一次询问 [ql,qr][ql,qr],从后往前检查每一个块。每次尝试加入这块内 [ql,qr][ql,qr] 的所有边。这在线段树上是 O(logm)O(\log m) 个区间,找出这些区间并把所有并查集合并。再检查此时是否还是一个二分图。若不是,则将并查集回退到这次操作前,暴力尝试加入该块内的所有边。否则检查下一个块。

这样的时间复杂度,设块长为 BB,是 O(m2logmB+mqnlogmB+qB)O(\frac{m^2\log m}{B}+\frac{mqn\log m}{B}+qB) 的,在 BB10510^5 时理论上可过。但是有个大问题,就是空间是 O(m2nB)O(\frac{m^2n}{B}) 显然爆炸。

解决这个问题可以考虑,其实我们并不关心每条边编号的具体位置,只关心它们是否在一个询问区间内。于是将所有 [ql,qr][ql,qr] 离线下来离散化,初始化每个块内的线段树时只用判断当前编号属于哪个区间就行了。

于是空间复杂度变成 O(mnqB)O(\frac{mnq}{B}),时间 O(m2logqB+mqnlogqB+qB)O(\frac{m^2\log q}{B}+\frac{mqn\log q}{B}+qB)。换个 short 就过了。

另外,作者在写这篇题解的时候突然发现,如果把线段树换成猫树可以做到 O(m2logqB+mqnB+qB)O(\frac{m^2\log q}{B}+\frac{mqn}{B}+qB),似乎会快很多。可能会补一个,也有可能咕咕咕了。

code:

#define L(i) ((i)*B+1)
#define R(i) min(((i)+1)*B,m)
bool Mbe;
int n,m,q,k,B=1e5+44,id[M],ls[Q<<1];
struct node{
	int u,v,w,id;
}a[M],b[M];
struct Node{
	int l,r;
}d[Q];
struct DSU{
	short fa[N<<1];
	void init(){
		rep(i,1,n+n){
			fa[i]=i;
		}
	}
	int fd(int x){
		return fa[x]==x?x:fa[x]=fd(fa[x]);
	}
	il void mrg(int x,int y){
		fa[fd(x)]=fd(y);
	}
};
struct SGT{
	DSU tr[Q<<3];
	void bld(int l,int r,int u){
		tr[u].init();
		if(l==r){
			return;
		}
		int mid=(l+r)>>1;
		bld(l,mid,u<<1),bld(mid+1,r,u<<1|1);
	}
	void upd(int l,int r,int u,int x,int y){
		tr[u].mrg(a[y].u,a[y].v+n);
		tr[u].mrg(a[y].u+n,a[y].v);
		if(l==r){
			return;
		}
		int mid=(l+r)>>1;
		if(x<=mid){
			upd(l,mid,u<<1,x,y);
		}else{
			upd(mid+1,r,u<<1|1,x,y);
		}
	}
	void qry(int l,int r,int u,int x,int y,DSU &D){
		if(r<x||l>y){
			return;
		}
		if(l>=x&&r<=y){
			rep(i,1,n+n){
				D.mrg(i,tr[u].fd(i));
			}
			return;
		}
		int mid=(l+r)>>1;
		qry(l,mid,u<<1,x,y,D),qry(mid+1,r,u<<1|1,x,y,D);
	}
}T[6];
il bool cmp(node x,node y){
	return x.w<y.w;
}
void Yorushika(){
	read(n,m,q);
	rep(i,1,m){
		read(a[i].u,a[i].v,a[i].w);
		a[i].id=i,b[i]=a[i];
	}
	sort(b+1,b+m+1,cmp);
	rep(i,1,m){
		id[b[i].id]=(i-1)/B;
	}
	rep(i,1,q){
		read(d[i].l,d[i].r);
		ls[i+i-1]=d[i].l,ls[i+i]=d[i].r+1;
	}
	sort(ls+1,ls+q+q+1);
	k=unique(ls+1,ls+q+q+1)-ls-1;
	rep(i,0,(m-1)/B){
		T[i].bld(1,k,1);
	}
	rep(i,1,m){
		int p=upper_bound(ls+1,ls+k+1,i)-ls-1;
		T[id[i]].upd(1,k,1,p,i);
	}
	rep(i,1,q){
		DSU x;x.init();
		int p=-1,l=lower_bound(ls+1,ls+k+1,d[i].l)-ls,r=lower_bound(ls+1,ls+k+1,d[i].r+1)-ls;
		drep(j,(m-1)/B,0){
			DSU tmp=x;
			T[j].qry(1,k,1,l,r-1,x);
			rep(k,1,n){
				if(x.fd(k)==x.fd(k+n)){
					p=j,x=tmp;
					break;
				}
			}
			if(~p){
				break;
			}
		}
		if(p==-1){
			puts("-1");
			continue;
		}
		drep(j,R(p),L(p)){
			if(b[j].id<d[i].l||b[j].id>d[i].r){
				continue;
			}
			if(x.fd(b[j].u)==x.fd(b[j].v)){
				printf("%d\n",b[j].w);
				break;
			}
			x.mrg(b[j].u,b[j].v+n);
			x.mrg(b[j].u+n,b[j].v);
		}
	}
}
bool Med;
signed main(){
	cerr<<(&Mbe-&Med)/1048576.0<<'\n';
	int t=1;
	//read(t);
	while(t--){
		Yorushika();
	}
}