Codeforces 2115B Gellyfish and Camellia Japonica 题解 [ 蓝 ] [ 图论建模 ] [ 拓扑排序 ]
Gellyfish and Camellia Japonica:以此纪念把我送上 CM 的一道题。
不难发现由于这些变量是具有传递性的,所以可以把序列上每个位置的每次修改都看做一个节点,对于一次 \((x,y,z)\) 的修改,就将 \(x,y\) 的当前版本向 \(z\) 的当前版本连边,以表示两者取 \(\min\) 的赋值操作。
进而考虑在每个节点的最终版本已知的情况下如何倒推出其余节点。先来弱化限制,假设节点 \(v\) 的值 \(a\) 已经确定,则对于给 \(v\) 赋值的两个节点 \(u_1,u_2\) 都必须满足值 \(\ge a\) 的下界限制,因为如果小于 \(a\) 则无法让 \(v\) 取到 \(a\)。
于是可以建反图后,跑一遍拓扑排序,递推出每个节点能取到的最小值,然后惊奇的发现让每个点取最小值正是一种构造方式!因为每个节点的下界已经被满足了,为了让被赋值的点能恰好赋到对应值而不变大,所以尽可能取最小值以满足赋值上界是一定是不劣的。
最后在构造出方案后,自行模拟一下判断方案是否合法即可。
时间复杂度 \(O(n+q)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=1000005,inf=0x3f3f3f3f,M=2000005;
int n,q,pos[N],id,dp[N],b[N],qx[N],qy[N],qz[N],tmp[N];
int h[N],rd[N],idx;
struct Edge{
int v,ne;
}e[M];
void add(int u,int v)
{
e[++idx]={v,h[u]};
h[u]=idx;
}
void init()
{
idx=0;
for(int i=1;i<=id;i++)
{
h[i]=0;
dp[i]=0;
rd[i]=0;
}
id=0;
}
bool check()
{
for(int i=1;i<=n;i++)
tmp[i]=dp[i];
for(int i=1;i<=q;i++)
{
int x=qx[i],y=qy[i],z=qz[i];
tmp[z]=min(tmp[x],tmp[y]);
}
for(int i=1;i<=n;i++)
if(tmp[i]!=b[i])return 0;
return 1;
}
void solve()
{
init();
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
pos[i]=++id;
}
for(int i=1;i<=q;i++)
{
int x,y,z;
scanf("%d%d%d",&qx[i],&qy[i],&qz[i]);
x=qx[i],y=qy[i],z=qz[i];
int u=++id;
add(u,pos[x]);
add(u,pos[y]);
rd[pos[x]]++;
rd[pos[y]]++;
pos[z]=u;
}
for(int i=1;i<=n;i++)
dp[pos[i]]=b[i];
queue<int>q;
for(int i=1;i<=id;i++)
if(rd[i]==0)q.push(i);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=h[u];i;i=e[i].ne)
{
int v=e[i].v;
rd[v]--;
if(rd[v]==0)q.push(v);
dp[v]=max(dp[v],dp[u]);
}
}
if(check()==0)
{
printf("-1\n");
return;
}
for(int i=1;i<=n;i++)printf("%d ",dp[i]);
printf("\n");
}
int main()
{
//freopen("sample.in","r",stdin);
//freopen("sample.out","w",stdout);
init();
int t;
scanf("%d",&t);
while(t--)solve();
return 0;
}

浙公网安备 33010602011771号