传送门
题解:
分段瞎搞:
1. n ≤ 500 n\leq 500 n≤500 直接暴力。
2.树,且不允许调用 check。
题目保证父亲小于自己,于是整体二分一下就行了。
3.一般情况+特性A。
随机选择 n / 2 n/2 n/2 个点 modify一下,然后看有多少个点被改变。
被改变意味着有奇数条边向前连,奇数>0,重复下去可以保证找到边。
期望有 n / 3 n/3 n/3 个点向前连了奇数条边。瞎搞即可。期望复杂度 O ( m log m ) O(m\log m) O(mlogm)。
代码:
#include "explore.h"
#ifndef ONLINE_JUDGE
#include "grader.cpp"
#endif
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
//modify( [0, N) )
//query ( [0, N) )
//report( [0, N), [0, N) )
//check ( [0, N) )
cs int N=2e5+7;
int n,m;
int op[N];
int p[N];
namespace Force{
void Main(){
for(int re i=0;i<n-1;++i){
modify(i);
for(int re j=i+1;j<n;++j)
if(op[j]!=query(j))
report(i,j),op[j]^=1;
}
}
}
namespace Tree{
int cur,tmp[N];
void solve(int l,int r,int ql,int qr){
if(ql>qr)return;if(l==r){
for(int re i=ql;i<=qr;++i)
report(l,p[i]);return;
}int mid=(l+r)>>1;
while(cur<mid)modify(++cur);
while(cur>mid)modify(cur--);
for(int re i=ql;i<=qr;++i)
if(p[i]<=mid||query(p[i]))
op[p[i]]=true;
else op[p[i]]=false;
int L=ql,R=qr;
for(int re i=ql;i<=qr;++i)
tmp[op[p[i]]?L++:R--]=p[i];
for(int re i=ql;i<=qr;++i)p[i]=tmp[i];
solve(l,mid,ql,R);solve(mid+1,r,L,qr);
}
void Main(){
for(int re i=0;i<n;++i)p[i]=i;
cur=-1;solve(0,n-1,1,n-1);
}
}
namespace Normal{
bool ban[N];
std::mt19937 R(time(0));
std::vector<int> G[N];
bool need_check;
void Report(int u,int v){
report(u,v);--m;
G[u].push_back(v);
G[v].push_back(u);
if(need_check){
ban[u]=check(u);
ban[v]=check(v);
}
}
int Qry(int u){
int res=query(u);
for(int v:G[u])
res^=op[v];
return res;
}
void solve(cs std::vector<int> &q,int l,int r){
if(q.empty())return ;
if(l==r){
for(int v:q)if(l!=v)
Report(p[l],p[v]);
return;
}int mid=(l+r)>>1;std::vector<int> ql,qr;
for(int re i=l;i<=mid;++i)
modify(p[i]),op[p[i]]=true;
for(int v:q)
if(v<=mid||Qry(p[v]))
ql.push_back(v);
else qr.push_back(v);
for(int re i=l;i<=mid;++i)
modify(p[i]),op[p[i]]=false;
solve(ql,l,mid);solve(qr,mid+1,r);
}
void Main(){
need_check=m>=n-1;
for(int re i=1;i<n;++i)p[i]=i;
while(m){
int nn=n;n=0;
for(int re i=0;i<nn;++i)
if(!ban[p[i]])p[n++]=p[i];
std::shuffle(p,p+n,R);
std::vector<int> q;
for(int i=0;i<n;++i)
q.push_back(i);
solve(q,0,n-1);
}
}
}
void explore(int _n,int _m){
n=_n,m=_m;
if(n<=500)
Force::Main();
else if(n%10==7)
Tree::Main();
else Normal::Main();
}