二轮省集day1

\(100+34+20\),没调出 t2 \(50\) 分。

还是有点过于自信了,怎么能认为 \(50\) min 能调出来的。部分分不能按顺序看。

调出来就进 A 队线了,那顺从了。

学校两个 D,太厉害了。


他必须活下去,因为山无处不在。

山的魅力在两个地方,登上它时,和远远望着它时。


且将新火试新茶,诗酒趁年华。


50pts.

首先需要会一个暴力的 \(O(\frac{n^3}w)\),这显然是不满的。考虑快速做 tarjan,这样后面做 \(m=0\) 就是简单的。唯一的问题就是 tarjan。假设我们不知道任何高深的竞赛图性质,下面做法不依赖竞赛图。

\(i\to j\) 连边当且仅当 \(a_i<b_j\&\& i<j\) 或者 \(b_i<a_j\&\& i>j\)。将 \(ab\) 分别排序,那么限制可以自然将一维变成后缀限制。考虑 tarjan 本质上是两部分,第一部分是用栈中的点来更新 \(low\),第二部分是访问所有没访问过的点。先考虑第二部分,由于我们已经将限制转成一维后缀了,只需考虑另一维,需要找出一个没访问过的点满足形如 \(j<i\) 的限制,直接两棵线段树维护后缀最值即可,访问到一个点时将最值对应更改。

第一部分看上去很不容易,限制是在栈中、有连边(此处是两个限制),总共三个限制,看上去是一个三维偏序。线段树很难做,考虑分块。每个数据结构维护按照 \(ab\) 排序后的相对位置,块内排序,维护后缀/前缀最值,在栈中这一限制总是单点修改,暴力重构即可。有连边的两个限制,第一个后缀限制可以直接分块自然消去,第二个值的大小限制直接块内二分也可消去,但是复杂度不太牛。注意到块的形态总是没有任何变化,不难 \(O(n\sqrt{n})\) 预处理出每个数在块内会二分到哪,查询时直接用就好。细节很多,需要想清楚大于还是小于,附上我的 10k 代码:

点击查看代码
#pragma GCC optimize(3)
#include<bits/stdc++.h>
// #define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)

template<typename T>
void read(T &x){
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
	x*=f;
}

std::stack<char>st;
template<typename T>
void print(T x){
	if(x==0) putchar('0');
	if(x<0) putchar('-'),x=-x;
	while(x) st.push((char)(x%10+'0')),x/=10;
	while(st.size()) putchar(st.top()),st.pop();
}

template<typename T>
void printsp(T x){
	print(x),putchar(' ');
}

template<typename T>
void println(T x){
	print(x),putchar('\n');
}

template<typename T,typename I>
bool chkmax(T &a,I b){
	if(a<b) return a=b,1;
	return 0;
}

template<typename T,typename I>
bool chkmin(T &a,I b){
	if(a>b) return a=b,1;
	return 0;
}

bool Mbe;

const int inf=1e9,MOD1=998244353,MOD2=1e9+7;

const int maxn=1e5+10;

int a[maxn],b[maxn],n,m;

namespace zhenjianuo2025{
	const int maxn=2510;
	bool e[maxn][maxn],in[maxn],E[maxn][maxn];
	std::bitset<maxn>bit[maxn];
	int dfn[maxn],low[maxn],cnt,stk[maxn],tp,bel[maxn],num,rd[maxn],df[maxn],topo[maxn],tot,sz;
	vint c[maxn],scc[maxn],d[maxn],f[maxn];
	void tarjan(int p){
		dfn[p]=low[p]=++cnt,stk[++tp]=p,in[p]=1;
		for(int i:c[p]){
			if(!dfn[i]) tarjan(i),chkmin(low[p],low[i]);
			else if(in[i]) chkmin(low[p],dfn[i]);
		}
		if(dfn[p]==low[p]){
			num++;
			while(stk[tp+1]!=p) in[stk[tp]]=0,bel[stk[tp]]=num,scc[num].push_back(stk[tp]),tp--;
		}
	}
	bool cmp(int x,int y){
		return df[x]<df[y];
	}
	void solve(){
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++){
				if(a[i]<b[j]) e[i][j]=1,e[j][i]=0;
				else e[i][j]=0,e[j][i]=1;
			}
		for(int i=1;i<=m;i++){
			int u,v;
			read(u),read(v);
			e[u][v]=e[v][u]=0;
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) if(e[i][j]) c[i].push_back(j);//,debug("%lld -> %lld\n",i,j);
		for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
		for(int i=1;i<=n;i++)
			for(int j:c[i]){
				if(bel[i]==bel[j]) continue;
				if(E[bel[i]][bel[j]]) continue;
				d[bel[i]].push_back(bel[j]),E[bel[i]][bel[j]]=1,rd[bel[j]]++;
			}
		std::queue<int>q;
		for(int i=1;i<=num;i++) if(!rd[i]) q.push(i);
		while(q.size()){
			int x=q.front();
			q.pop();
			topo[++tot]=x,df[x]=tot;
			for(int i:d[x])
				if(--rd[i]==0) q.push(i);
		}
		for(int i=1;i<=num;i++) bit[i].reset(),bit[i][i]=1;
		for(int i=num;i>=1;i--){
			int x=topo[i];
			std::sort(d[x].begin(),d[x].end(),cmp);
			for(int j:d[x]){
				if(bit[x][j]==1) continue;
				sz++,f[x].push_back(j);
				bit[x]|=bit[j];
			}
		}
		for(int i=1;i<=num;i++) sz+=(scc[i].size()==1?0:scc[i].size());
		println(sz);
		for(int i=1;i<=num;i++){
			int hd=scc[i][0],lst;
			for(int j=1;j<scc[i].size();j++) lst=scc[i][j],printsp(hd),println(lst),hd=lst;
			if(scc[i].size()>1) printsp(lst),println(scc[i][0]);
		}
		for(int i=1;i<=num;i++)
			for(int j:f[i]) printsp(scc[i][0]),println(scc[j][0]);
	}
}

bool dcy;

namespace network_error{
	const int maxn=1e5+10,N=2510;
	const int B=450;
	std::bitset<N>bit[N];
	int dfn[maxn],stk[maxn],low[maxn],tp,cnt,tot,num,in[maxn],Q[maxn],H[maxn],posa[maxn],posb[maxn];
	int bl[B],br[B],c[maxn],blk,d[maxn],ch[maxn][500],pc[maxn],pd[maxn],belk[maxn],bel[maxn];
	int hmi[maxn],qmi[maxn],ch2[maxn][B],per[maxn];
	bool vis[maxn];
	pii b_[maxn],a_[maxn];
	vint scc[maxn];
	int qwq;
	struct SegmentTree{
		int l[maxn*2],r[maxn*2],mi[maxn*2],mx[maxn*2],ls[maxn*2],rs[maxn*2],tot;
		void clear(){
			tot=0;
		}
		void push_up(int p){
			mi[p]=std::min(mi[ls[p]],mi[rs[p]]);
			mx[p]=std::max(mx[ls[p]],mx[rs[p]]);
		}
		int build(int L,int R){
			int p=++tot;
			l[p]=L,r[p]=R;
			if(L==R) return mi[p]=a_[L].se,mx[p]=b_[L].se,p;
			int mid=(L+R)>>1;
			ls[p]=build(L,mid),rs[p]=build(mid+1,R);
			push_up(p);
			return p;
		}
		void update(int p,int pos,int tp){
			if(l[p]==r[p]){
				if(tp==0) mi[p]=inf;
				else mx[p]=-inf;
				return ;
			}
			int mid=(l[p]+r[p])>>1;
			if(mid>=pos) update(ls[p],pos,tp);
			else update(rs[p],pos,tp);
			push_up(p);
		}
		void modify(int &a,int b,int tp){
			if(tp==0) chkmin(a,b);
			else chkmax(a,b);
		}
		int query(int p,int L,int R,int tp){
			if(L>R){
				if(tp==0) return inf;
				else return -inf;
			}
//			debug("[%lld,%lld] %lld %lld\n",l[p],r[p],mi[p],mx[p]);
//			qwq++;
//			if(qwq>=10) exit(0);
			if(l[p]>=L&&r[p]<=R) return (tp==0)?mi[p]:mx[p];
//			if(l[p]==r[p]) return (tp==0)?mi[p]:mx[p];
			int mid=(l[p]+r[p])>>1,res;
			if(tp==0) res=inf;
			else res=-inf;
			if(mid>=L) modify(res,query(ls[p],L,R,tp),tp);
			if(R>mid) modify(res,query(rs[p],L,R,tp),tp);
			return res;
		}
	}ds;
	void tarjan(int p){
		// if(p%1000==0) debug("p=%lld\n",p);
		// if(p==95000) dcy=1;
		// if(dcy) debug("p=%lld\n",p);
		// debug("p=%d %d %d\n",p,Q[p],H[p]);
		vis[p]=1;
		dfn[p]=low[p]=++tot,stk[++tp]=p,in[p]=1;
		ds.update(1,posa[p],0),ds.update(1,posb[p],1);
		int w1=belk[posa[p]],w2=belk[posb[p]];
		qmi[bl[w1]]=dfn[c[bl[w1]]],hmi[br[w2]]=dfn[d[br[w2]]];
		for(int i=bl[w1]+1;i<=br[w1];i++) qmi[i]=std::min(qmi[i-1],dfn[c[i]]);
		for(int i=br[w2]-1;i>=bl[w2];i--) hmi[i]=std::min(hmi[i+1],dfn[d[i]]);
		int qr=Q[p];
		// if(p==1) debug("%lld\n",bel[qr]);
		for(int i=belk[qr]+1;i<=blk;i++){
			if(qr==n+1) break;
			// if(qmi[ch[p][i]]==0&&p==27401&&ch[p][i]>=bl[i]) debug("i=%lld ch=%lld [%lld,%lld]\n",i,ch[p][i],bl[i],br[i]);
			if(ch[p][i]>=bl[i]) chkmin(low[p],qmi[ch[p][i]]);
		}
		// debug("p=%d low=%d\n",p,qr);
		// if(p==27401) debug("%lld %lld %lld\n",low[p],qr,belk[qr]);
		for(int i=qr;i<=br[belk[qr]];i++){
			if(qr==n+1) break;
			// if(pc[i]<p&&low[pc[i]]==0&&p==27401) debug("i=%lld pc=%lld low=%lld\n",i,pc[i],low[pc[i]]);
			if(pc[i]<p)chkmin(low[p],dfn[pc[i]]);//,debug("i=%d pc=%d dfn=%d\n",i,pc[i],dfn[pc[i]]);	
		}
		// debug("p=%d low=%d\n",p,low[p]);
		// if(p==27401) debug("%lld\n",low[p]);
		int ql=H[p];
		for(int i=belk[ql]+1;i<=blk;i++){
			if(ql==n+1) break;
			// if(hmi[ch2[p][i]+1]==0&&p==27401&&ch2[p][i]!=br[i]) debug("i=%lld ch=%lld [%lld,%lld]\n",i,ch2[p][i],bl[i],br[i]);
			if(ch2[p][i]!=br[i]) chkmin(low[p],hmi[ch2[p][i]+1]);
		}
		for(int i=ql;i<=br[belk[ql]];i++){
			if(ql==n+1) break;
			if(pd[i]>p)chkmin(low[p],dfn[pd[i]]);
		}
		// debug("p=%d low=%d\n",p,low[p]);
		// if(p==27401) debug("%lld\n",low[p]);
		while(1){
			int x=ds.query(1,Q[p],n,0);
//			debug("x=%lld\n",x); 
			if(x>p) break;
			// if(vis[x]) debug("p=%lld x=%lld\n",p,x);
			tarjan(x),chkmin(low[p],low[x]);
		}
		while(1){
			int x=ds.query(1,H[p],n,1);
			if(x<p) break;
			// if(vis[x]) debug("p=%lld x=%lld\n",p,x);
			tarjan(x),chkmin(low[p],low[x]);
		}
		// if(p==27401) debug("%lld %lld\n",dfn[p],low[p]);
		if(dfn[p]==low[p]){
			num++;
			// debug("in\n");
			while(stk[tp+1]!=p){
				int x=stk[tp];
				// debug("pop %d\n",x);
				dfn[x]=inf;
				int w1=belk[posa[x]],w2=belk[posb[x]];
				qmi[bl[w1]]=dfn[c[bl[w1]]],hmi[br[w2]]=dfn[d[br[w2]]];
				for(int i=bl[w1]+1;i<=br[w1];i++) qmi[i]=std::min(qmi[i-1],dfn[c[i]]);
				for(int i=br[w2]-1;i>=bl[w2];i--) hmi[i]=std::min(hmi[i+1],dfn[d[i]]);
				tp--;
//				debug("x=%lld num=%lld\n",x,num);
				bel[x]=num;
				in[x]=0;
				scc[num].push_back(x);
			}
			// debug("ok\n");
		}
	}
	bool cmp_(int x,int y){
		int f=scc[x][0],g=scc[y][0];
		if(f<g){
			if(a[f]<b[g]) return 1;
			return 0;
		}else{
			if(a[g]<b[f]) return 0;
			return 1;
		}
	}
	void solve(){
		for(int i=1;i<=n;i++) b_[i].fi=b[i],b_[i].se=i,a_[i].fi=a[i],a_[i].se=i;
		std::sort(b_+1,b_+n+1);
		std::sort(a_+1,a_+n+1);
		for(int i=1;i<=n;i++){
			// debug("i=%lld %lld %lld %lld %lld\n",i,a_[i].fi,a_[i].se,b_[i].fi,b_[i].se);
			int l=1,r=n;
			while(l<=r){
				int mid=(l+r)>>1;
				// debug("[%lld,%lld] mid=%lld %lld\n",l,r,mid,b_[mid].fi);
				if(b_[mid].fi<a_[i].fi) l=mid+1;
				else r=mid-1;
			}
//			debug("r=%lld\n",r);
			H[a_[i].se]=r+1;
			l=1,r=n;
			while(l<=r){
				int mid=(l+r)>>1;
				if(a_[mid].fi<b_[i].fi) l=mid+1;
				else r=mid-1;
			}
			Q[b_[i].se]=r+1;
			posa[a_[i].se]=i,posb[b_[i].se]=i;
		}
		// return ;
		blk=0;
		for(int i=1;i<=n;i++) pc[i]=c[i]=a_[i].se,pd[i]=d[i]=b_[i].se;
		for(int i=1;i<=n;i++){
			blk++;
			bl[blk]=i,br[blk]=std::min(n,i+B-1);
			std::sort(c+bl[blk],c+br[blk]+1),std::sort(d+bl[blk],d+br[blk]+1);
			int z=1,z_=1;
			for(int j=bl[blk];j<=br[blk];j++){
				belk[j]=blk;
				while(z<=c[j]) ch[z][blk]=j-1,z++;
				while(z_<=d[j]) ch2[z_][blk]=j-1,z_++;
			}
			while(z<=n) ch[z][blk]=br[blk],z++;
			while(z_<=n) ch2[z_][blk]=br[blk],z_++;
			i=br[blk];
		}
		// debug("ok\n");
		ds.clear(),ds.build(1,n);
		for(int i=1;i<=n;i++) dfn[i]=low[i]=inf,qmi[i]=hmi[i]=inf;
		for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i);
		for(int i=1;i<=num;i++) per[i]=i;
		std::sort(per+1,per+num+1,cmp_);
		int sz=0;
		for(int i=1;i<=num;i++) if(scc[i].size()!=1) sz+=scc[i].size();
		println(sz+num-1);
		for(int i=1;i<=num;i++){
			if(scc[i].size()==1) continue;
			int lst=scc[i][0];
			int bg=lst;
			for(int j=1;j<scc[i].size();j++) lst=scc[i][j],printsp(scc[i][j-1]),println(lst);
			printsp(lst),println(bg);
		}
		for(int i=1;i<num;i++){
			// debug("i=%d\n",i);
			// for(int j:scc[i]) debug("%d\n",j);
			printsp(scc[per[i]][0]),println(scc[per[i+1]][0]);
		}
	}
}

bool Men;

signed main(){
	// freopen("data.in","r",stdin),freopen("corolla.out","w",stdout);
//	freopen("ex_corolla3.in","r",stdin),freopen("my.out","w",stdout);
	debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
	read(n),read(m);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) read(b[i]);
	if(n<=2500){
		zhenjianuo2025::solve();
		return 0;
	}
	network_error::solve();
	debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
/*
5 0
1 3 4 9 7
10 8 2 5 6

5 0
3 1 5 6 7
10 4 2 8 9

5 0
7 9 5 3 10
1 8 2 6 4
*/

今天喝了七瓶水。

posted @ 2025-04-30 23:14  BYR_KKK  阅读(35)  评论(0)    收藏  举报