P3250 [HNOI2016]网络 题解


题面

一个显然的做法是树剖之后dfs序线段树套时间线段树,直接做的复杂度是 \(O(n\log^3 n)\)。其实也可以把询问离线下来,做一个线段树分治,用树套树维护。

这样做比较麻烦,所以考虑另外一种思路:二分答案。因为有很多询问,不妨放在一起二分,所以可以想到整体二分。使用类似树上差分的思想,对于一条路径 \(u\rightarrow lca(u,v)\to v\),如果它的权值大于 \(mid\),在用dfs序建的树状数组上给 \(u,v\) 加一,给 \(lca\)\(fa[lca]\) 减一,对于询问统计经过该点的路径条数是否等于此时权值大于 \(mid\) 的路径数量,向两边递归即可。

这道题还有使用路径交等一系列科技的 \(1\log\) 做法,太神了本人(当时可能)并不会……然而现在估计也不会。

点击查看代码
#include
#include
#include
inline int max(const int &a,const int &b){return a>b?a:b;}
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int rd(){
	int res=0;char c=getchar();
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0');
	return res;
}
void wt(int x){if(x<0){putchar('-'),wt(-x);return;}if(x>9)wt(x/10);putchar(x%10+'0');}
const int N=2e5+13;
struct Node{
	int op,u,v,t,x,id,ans;
	bool operator <(const Node &a)const{return idmaxson) maxson=siz[v],son[u]=v;
	}
	dfnr[u]=++dfs_clock;
}
void dfs2(int u,int topf){
	top[u]=topf;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
	}
}
inline int lca(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]r) return;
	if(L==R){
		for(int i=l;i<=r;++i)
			if(q[i].op==2) q[i].ans=L;
		return;
	}
	int mid=(L+R)>>1,lt=0,rt=0,tmp=0;
	for(int i=l;i<=r;++i){
		if(q[i].op!=2){
			if(q[i].x<=mid) lq[++lt]=q[i];
			else{
				int v=(q[i].op?-1:1);tmp+=v;
				if(q[i].u&&q[i].v) T.add(dfnl[q[i].u],v),T.add(dfnl[q[i].v],v),T.add(dfnl[q[i].t],-v);
				if(fa[q[i].t]) T.add(dfnl[fa[q[i].t]],-v);
				rq[++rt]=q[i];
			}
		}
		else{
			if(T.sum(dfnr[q[i].x])-T.sum(dfnl[q[i].x]-1)==tmp) lq[++lt]=q[i];
			else rq[++rt]=q[i];
		}
	}
	for(int i=l;i<=r;++i){
		if(q[i].op==2||q[i].x<=mid) continue;
		int v=(q[i].op?1:-1);
		T.add(dfnl[q[i].u],v),T.add(dfnl[q[i].v],v),T.add(dfnl[q[i].t],-v);
		if(fa[q[i].t]) T.add(dfnl[fa[q[i].t]],-v);
	}
	for(int i=1;i<=lt;++i) q[l+i-1]=lq[i];
	for(int i=1;i<=rt;++i) q[l+lt+i-1]=rq[i];
	solve(L,mid,l,l+lt-1);
	solve(mid+1,R,l+lt,r);
}
int main(){
	n=rd(),m=rd();
	for(int i=1,u,v;i