agc041 **Balancing Network** 题解
agc041 Balancing Network 题解
很有趣的构造题:
Case 1
如何使流汇聚到一条边上?
可以倒推。
假设最后都汇聚到\(x\)。
维护一个集合\(S\),表示可以有流量的边,初始\(S=\{x\}\)。
从后往前遇到边\(x_i,y_i\)。如果\(x_i,y_i\)之一在\(S\)中,则加入\(x_i,y_i\)。
最后判断一下\(S\)是否是全集即可,复杂度\(O(nm)\)。
优化:
构造一个\(n\)个点的图。
可以将\(x_i,y_i\)看作在\(x_i,y_i\)中间连一个权值为\(i\)的边。
一个点\(y\)最终能在集合中当且仅当存在一个路径\(x,s_1,s_2...s_n,y\),满足边\(s_i,s_{i+1}\)的权值\(\leq s_{i+1},s_{i}\)。
为了避免重边,可以对于\(x_i,y_i\)新建两个点,有颜色\(x_i,y_i\)。
问题就是能否从一个点出发到达所有颜色,\(bitset\)优化即可。
时间复杂度\(O(\frac{nm}{w})\)。
Case 2
解法1:
我的想法是和\(1\)差不多做。
从后往前倒推,维护一个二元组\((x,y)\)。
表示最终必须保证\(x,y\)有流量。
可以\(dp\)解决,时间复杂度\(O(mn)\)。
但是注意到若\(n\geq 500\),则一定存在一个\(x,y\)满足\(x,y\)中没有边,可以很容易构造。
所以时间和空间复杂度为\(O(m\sqrt m)\)。
解法2:
题解做法:
从后往前。
注意到若\(n\geq 3\),则一定有解。
对于每一条边维护一个数组\(B_i\)表示从\(i\)出发最终会在哪里结束?
若\(B_i\)最终全相等就不行。
对于一个\(x,y\),本质上是令\(B_x\Leftarrow B_y\)或者\(B_y\Leftarrow B_x\)。
可以发现\(n\geq 3\)是不存在只有\(B_x,B_y\)两种数,且个数都为\(1\)。
直接构造的复杂度为\(O(N)\) 。
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define rep(a,b) for(int a=0;a<b;++a)
#define LL long long
#define PB push_back
#define POB pop_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
const int MAXN=1e5+1;
int n,m,t;
int x[MAXN],y[MAXN];
int pre[MAXN];
bool ok[MAXN];
bitset<50000> vis[100001];
void construct1(){
rb(i,1,m){
vis[i].set(x[i]);
vis[i].set(y[i]);
if(pre[x[i]]) vis[i]|=vis[pre[x[i]]];
if(pre[y[i]]) vis[i]|=vis[pre[y[i]]];
pre[x[i]]=pre[y[i]]=i;
}
rep(i,n){
if(vis[pre[i]].count()==n){
ok[i]=1;
string answer;
rl(j,m,1){
if(ok[x[j]]||ok[y[j]]){
if(ok[x[j]]) answer.PB('^');
else answer.PB('v');
ok[x[j]]=ok[y[j]]=1;
}
else{
answer.PB('v');
}
}
reverse(ALL(answer));
cout<<answer<<endl;
return ;
}
}
cout<<-1<<endl;
return ;
}
char ans[100000+20];
pair<short,short> dp[100000+20][2][500];
int pr[100000+20][2][500];
mp gt(int i,int a,int b){
if(b==x[i]||b==y[i]) swap(a,b);
if(a==x[i]) return II(0,b);
return II(1,b);
}
void recover(int i,short a,short b){
if(i==0) return ;
auto A=dp[i][gt(i,a,b).FIR][gt(i,a,b).SEC];
auto B=pr[i][gt(i,a,b).FIR][gt(i,a,b).SEC];
if(A==II(a,b)){
if(b==x[i]||b==y[i]) swap(a,b);
if(a==x[i]){
ans[i]='^';
}
}
else{
tie(a,b)=A;
if(b==x[i]||b==y[i]) swap(a,b);
if(a==y[i]){
ans[i]='^';
}
}
recover(B,A.FIR,A.SEC);
}
void construct2(){
if(n>=500){
map<mp,int> gg;
rb(i,1,m) gg[II(x[i],y[i])]=gg[II(y[i],x[i])]=1;
rep(i,n){
rep(j,i){
if(gg[II(i,j)]==0){
rb(k,1,m){
if(x[k]==i||x[k]==j){
cout<<'^';
}
else{
cout<<"v";
}
}
cout<<endl;
return ;
}
}
}
return;
}
rb(i,0,m) rep(j,2) rep(k,500) dp[i][j][k]=II(-1,-1);
rb(i,1,m) ans[i]='v';
rb(i,1,m){
rep(k,n){
if(k!=x[i]&&k!=y[i]){
int a,b,j;
a=min(k,x[i]);
b=max(k,x[i]);
int c,d;
c=min(k,y[i]);
d=max(k,y[i]);
j=max(pre[a],pre[b]);
if(j==0||dp[j][gt(j,a,b).FIR][gt(j,a,b).SEC].FIR!=-1){
dp[i][gt(i,c,d).FIR][gt(i,c,d).SEC]=II(a,b);
dp[i][gt(i,a,b).FIR][gt(i,a,b).SEC]=II(a,b);
pr[i][gt(i,c,d).FIR][gt(i,c,d).SEC]=j;
pr[i][gt(i,a,b).FIR][gt(i,a,b).SEC]=j;
continue;
}
j=max(pre[c],pre[d]);
if(j==0||dp[j][gt(j,c,d).FIR][gt(j,c,d).SEC].FIR!=-1){
dp[i][gt(i,c,d).FIR][gt(i,c,d).SEC]=II(c,d);
dp[i][gt(i,a,b).FIR][gt(i,a,b).SEC]=II(c,d);
pr[i][gt(i,c,d).FIR][gt(i,c,d).SEC]=j;
pr[i][gt(i,a,b).FIR][gt(i,a,b).SEC]=j;
// continue;
}
}
}
// cout<<i<<" "<<dp[i].size()<<endl;
pre[x[i]]=pre[y[i]]=i;
}
rep(i,n) rep(j,i) if(max(pre[i],pre[j])==0||dp[max(pre[i],pre[j])][gt(max(pre[i],pre[j]),j,i).FIR][gt(max(pre[i],pre[j]),j,i).SEC].FIR!=-1){
recover(max(pre[i],pre[j]),j,i);
rb(i,1,m) cout<<ans[i];
cout<<endl;
return ;
}
cout<<"-1\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>t;
rb(i,1,m) cin>>x[i]>>y[i],x[i]--,y[i]--;
if(t==1) construct1();
else construct2();
return 0;
}