二轮省集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
*/
今天喝了七瓶水。