[uoj751]神隐
假设有\(2k\)次询问,考虑让每条边恰在\(k\)次询问中出现
对于\(k\)的上界,均满足\({2k\choose k}\ge n-1\),即可令每条边出现状态不全相同
此时,对于任意两点\((x,y)\),有\((x,y)\in E\iff x,y\)恰在\(k\)次询问中连通
\(x,y\)连通\(\iff x\)到\(y\)路径上所有边均被选,当(路径上)边数\(\ge 2\)时交\(<k\)
暴力实现即可做到\(o(n^{2}\log n)\),参考这里的算法四优化后,可以做到\(o(n2^{k})\)
换一个角度,对于任意一点\(x\),有\(x\)度数为\(1\iff x\)恰在\(k\)次询问中为"孤立点"
\(x\)为孤立点\(\iff\)与\(x\)相邻的边均未被选,当(与\(x\)相邻的)边数\(\ge 2\)时并\(>k\)
同时,其余\(k\)次询问\(x\)所在连通块的交大小为\(2\),且另一个点即与\(x\)相邻的点
记与\(x\)相邻的点为\(y\),这\(k\)次询问中\((x,y)\)均被选,则其余边总存在某次未被选
暴力实现即可做到\(o(n^{2}\log n)\),瓶颈在于求交,下面考虑优化:
考虑所有\(x\)被删除顺序的逆序,即以最后所剩下的点开始搜索的bfs序
此时,与\(x\)相邻的点即这\(k\)次询问 \(x\)所在连通块中bfs序最小的点 中bfs序最大的点
记\(x\)的父亲为\(y\),其在这\(k\)次询问中均与\(x\)连通,即最终的点bfs序不超过\(y\)
记\(y\)的父亲为\(z\),则\((y,z)\)未被选时bfs序最小的点即\(y\),因此最终的点bfs序不小于\(y\)
时间复杂度为\(o(n\log n)\),可以通过
#include<bits/stdc++.h>
#include "tree.h"
using namespace std;
#define N 150000
#define ll long long
int n,k,pos[N][30],sz[30][N],cnt[N],dfn[N],vis[N][30],mn[30][N];
ll sum[30][N];queue<int>q;vector<int>v[30];
vector<pair<int,int> >ans;vector<vector<int> >res[30];
vector<pair<int,int> >solve(int nn){
n=nn,k=(n<=2000 ? 7 : 10);
for(int i=0;i<(k<<1);i++)v[i].resize(n-1);
for(int S=0,j=0;j<n-1;S++)
if (__builtin_popcount(S)==k){
for(int i=0;i<(k<<1);i++)
if ((S>>i)&1)v[i][j]=1;
j++;
}
for(int i=0;i<(k<<1);i++){
if (!v[i].empty())res[i]=query(v[i]);
else{
for(int j=0;j<n;j++)res[i].push_back(vector<int>{j});
}
for(int t=0;t<res[i].size();t++){
for(int j:res[i][t])pos[j][i]=t,sz[i][t]++,sum[i][t]+=j;
if ((sz[i][t]==1)&&(++cnt[sum[i][t]]==k))q.push(sum[i][t]);
}
}
while (!q.empty()){
int j=q.front();q.pop();
dfn[j]=n-dfn[n],dfn[n]++;
for(int i=0;i<(k<<1);i++){
int t=pos[j][i];sum[i][t]-=j;
if ((--sz[i][t]==1)&&(++cnt[sum[i][t]]==k))q.push(sum[i][t]);
if (!sz[i][t])vis[j][i]=1;
}
}
for(int i=0;i<(k<<1);i++)
for(int t=0;t<res[i].size();t++){
int Mn=-1;
for(int j:res[i][t])
if ((Mn<0)||(dfn[Mn]>dfn[j]))Mn=j;
mn[i][t]=Mn;
}
for(int j=0;j<n;j++){
if (dfn[j]==1)continue;
int to=-1;
for(int i=0;i<(k<<1);i++)
if (!vis[j][i]){
int Mn=mn[i][pos[j][i]];
if ((to<0)||(dfn[to]<dfn[Mn]))to=Mn;
}
ans.push_back(make_pair(j,to));
}
return ans;
}