2023.8.11

不背图论板子要反省一下自己了。

A

[ABC206E] Divide Both

\[\sum_{x=L}^{R}\sum_{y=L}^{R}[(x,y)\not=1,\frac{x}{(x,y)}\not=1,\frac{y}{(x,y)}\not=1] \]

\(1\le L\le R\le 10^6\).

先容斥。假定 \(n\le m\).

\[\sum_{d=2}^{n}\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}[x\perp y,x\not=1,y\not=1] \]

如果 \(x=1\)\(y=1\) 那么 \((x,y)\) 一定被统计了,要减去 \(\displaystyle\lfloor\frac{n}{d}\rfloor+\lfloor\frac{m}{d}\rfloor-1\).

\[\Bigg(\sum_{d=1}^{n}\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}[x\perp y]-(\lfloor\frac{n}{d}\rfloor+\lfloor\frac{m}{d}\rfloor-1)\Bigg)-\sum_{x=1}^{n}\sum_{y=1}^{m}[x\perp y] \]

前面一小块就是 \(nm\),后面是 \(\displaystyle\sum_{p=1}^{n}\mu(p)\lfloor\frac{n}{p}\rfloor\lfloor\frac{m}{p}\rfloor\).

时间复杂度 \(O(n)\).

当然不用莫反估计也能做。


B

P4334 [COI2007] Policija

一张无向连通图,问

  • 割边后两点的连通性

  • 割点后两点的连通性

\(n\le 10^5\)\(m\le 5\times 10^5\)\(q\le 3\times 10^5\).

luogu \(\rm ML=62.5MiB\).

tarjan 的话第一问更简单,但是考场上过载了。

先来看一下 part2.

一个普通的想法是点双之后判断删点在不在两点的路径上,这个直接拍到圆方树上做就好了。

具体来说直接倍增把三者的 lca 弄出来判一判即可。当然也可以写个树剖。

再看下 part1.

只需要考虑边为桥的情况。那么这两个点应该与同一个方点相邻。

这样问题就又变成了 part2,把这个桥对应的方点拉出来做一遍即可。

时间复杂度 \(O(n\log n)\),空间复杂度 \(O(n\sim n\log n)\).

求桥时圆方树的算法里做 low[u]=min(low[u],dfn[v]) 是一定不能爬父边的,虽然它不会对圆方树的结构产生影响。

#include<bits/stdc++.h>
#define ll long long
#define N 100010
#define pb push_back
#define mp make_pair
#define mit map<pair<int,int>,int>::iterator
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
bool gets(){
	char ch=getchar();
	while(ch!='A'&&ch!='C')ch=getchar();
	return ch=='C';
}
int n,m,q,cnt;
vector<int>e[N],T[N<<1];
int dfn[N],low[N],tim;
int st[N],tp;
map<pair<int,int>,int>bri;
void tarjan(int u,int fa){
	low[u]=dfn[u]=++tim;
	st[++tp]=u;
	for(int v:e[u]){
		if(!dfn[v]){
			tarjan(v,u),low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				cnt++;
				if(low[v]>dfn[u])
					bri[minmax(u,v)]=cnt;
				for(int x=0;x!=v;tp--){
					x=st[tp];
					T[cnt].pb(x),T[x].pb(cnt);
				}
				T[cnt].pb(u),T[u].pb(cnt);
			}
		}
		else if(v!=fa)low[u]=min(low[u],dfn[v]);
	}
}
int fa[N<<1],dep[N<<1],siz[N<<1],son[N<<1];
int top[N<<1],dfc;
void dfs1(int u){
	siz[u]=1;
	for(int v:T[u]){
		if(dep[v])continue;
		fa[v]=u,dep[v]=dep[u]+1;
		dfs1(v),siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])son[u]=v;
	}
}
void dfs2(int u,int t){
	top[u]=t;
	if(son[u])dfs2(son[u],t);
	for(int v:T[u])
		if(fa[v]==u&&v!=son[u])dfs2(v,v);
}
bool crs(int x,int y,int z){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		if(top[x]==top[z]&&dep[z]<=dep[x])return true;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	if(top[x]==top[z]&&dep[z]>=dep[x]&&dep[z]<=dep[y])return true;
	return false;
}
int main(){
	n=read(),m=read();
	cnt=n;
	for(int i=1,u,v;i<=m;i++){
		u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}
	tarjan(1,0);
	dep[1]=1,dfs1(1),dfs2(1,1);
	q=read();
	for(int opt,a,b,c,d;q;q--){
		opt=read(),a=read(),b=read(),c=read();
		if(opt==1){
			d=read();
			mit it=bri.find(minmax(c,d));
			if(it==bri.end())puts("yes");
			else puts(crs(a,b,it->second)?"no":"yes");
		}
		else puts(crs(a,b,c)?"no":"yes");
	}
	
	return 0;
}

C

P5786 [CQOI2008] 传感器网络

求 DAG 的一颗生成树,且根为 \(n\)(保证图上 \(in_n=0\)),试让所有非根节点的儿子数的最大值最小,并给出 \(0\sim n-1\) 的字典序最小的父亲序列。DAG 不连通输出 \(-1\).

\(n\le 50\).

不考虑字典序,先最小化儿子数的最大值,容易二分一个 \(k\),建图直接跑最大流,\(maxflow=n\) 说明 \(k\) 合法。

再去想字典序的问题,假设已经确定 \(fa_{0\sim n-1}\),枚举 \(fa_i\).

假设选择 \(fa_i\),再建一遍图跑最大流,为 \(n\) 说明 \(fa_i\) 合法,继续枚举 \(i+1\).

要跑 \(n^2\) 次网络流,不太会分析复杂度,应该是 \(O(n^4\sim n^5)\).


D

不会。

posted @ 2023-08-11 15:14  SError  阅读(24)  评论(0编辑  收藏  举报