AT5696 [AGC041E] Balancing Network
题面传送门
先来考虑\(T=1\)。
可以枚举最后的那一行是啥,那么刚开始当前行是可以达到的。
接下来从后往前枚举边,如果这条边有一个端点可以走到,那么另一个端点也可以走到。
发现这个可以并行,然后就可以bitset优化,时间复杂度\(O(\frac{nm}{w})\)
再考虑\(T=2\)。
首先\(n=2\)显然无解。然后似乎接下面都有解了?
仍然考虑从后往前构造,每个线维护\(Id_i\)与\(cnt_i\)表示这条线会到哪里以及以这条线结束的线的数量。
然后一条边\(x_i,y_i\),如果\(cnt_{Id_{x_i}}=n-1\),那么就让\(x_i\)指向\(y_i\),反之亦然。
发现两边都是\(n-1\)的时候会导致无解,但是在\(n>2\)时不可能,因此一定有解。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (50000+5)
#define M (100000+5)
#define K (20+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,T,X[M],Y[M],Ans[M];
namespace Solve1{
bitset<N> F[N],Pus,ToT;I void print(int x){int i;ToT[x]=1;for(i=m;i;i--) ToT[X[i]]?(ToT[Y[i]]=1,Ans[i]=1):(ToT[X[i]]=ToT[Y[i]],Ans[i]=0);for(int i=1;i<=m;i++) Pc(Ans[i]?'^':'v');}
I void calc(){
int i;for(i=1;i<=n;i++) Pus[i]=1,F[i][i]=1;for(i=m;i;i--) F[X[i]]|=F[Y[i]],F[Y[i]]|=F[X[i]];for(i=1;i<=n;i++) Pus&=F[i];
for(i=1;i<=n;i++) if(Pus[i]){print(i);return;}puts("-1");
}
}
namespace Solve2{
int Id[N],Ct[N];
I void calc(){
if(n==2){puts("-1");return;}int i;for(i=1;i<=n;i++) Id[i]=i,Ct[i]=1;for(i=m;i;i--) Ct[Id[X[i]]]==n-1?(Ct[Id[X[i]]]--,Id[X[i]]=Id[Y[i]],Ct[Id[X[i]]]++,Ans[i]=1):(Ct[Id[Y[i]]]--,Id[Y[i]]=Id[X[i]],Ct[Id[Y[i]]]++,Ans[i]=0);
for(i=1;i<=m;i++) Pc(Ans[i]?'v':'^');
}
}
int main(){
freopen("1.in","r",stdin);
int i;scanf("%d%d%d",&n,&m,&T);for(i=1;i<=m;i++) scanf("%d%d",&X[i],&Y[i]);
if(T==1) Solve1::calc();else Solve2::calc();
}