题解:P12088 [RMI 2019] 还原 / Restore Arrays
Bill_luogu · · 题解
此题使用差分约束,想要
STEP 1:什么是差分约束系统?
模板题:P5960 【模板】差分约束
差分约束系统就是由
STEP 2:用什么算法求解?
观察
STEP 3:如何建边?
设
STEP 4:从哪个点开始?
建一个超级源节点
怎么知道这是对的呢?
很简单,设
STEP 5:用哪个最短路算法?
很多人都会想到用 dijkstra ,当你提交后会发现花花绿绿的,这是因为 dijkstra 判不了无解(即有负环),所以使用 SPFA 或者 Bellman-Ford ,本蒟蒻使用的是 SPFA 。
STEP 6:一些小问题
再次提交,发现又是花花绿绿。再次回到题目,由于是
AC Code:
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
queue<int> q;
vector<int> v[10010];
int dis[100010],cnt[10010];
bool vis[10010];
int n,m;
bool spfa()
{
while(q.size())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int i=0;i<v[x].size();i+=2)
{
int y=v[x][i],w=v[x][i+1];
if(dis[x]+w>=dis[y])continue;
dis[y]=dis[x]+w;
cnt[y]=cnt[x]+1;
if(cnt[y]>=min(n,(int)3e3))//玄学优化
{
cout<<"-1";//无解
return 0;
}
if(!vis[y])
{
q.push(y);
vis[y]=1;
}
}
}
return 1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int l,r,k,val;
cin>>l>>r>>k>>val;
l++,r++;//本蒟蒻习惯下标从 1 开始
if(val==1)
{
v[r].push_back(l-1);
v[r].push_back(l+k-2-r);
}
else
{
v[l-1].push_back(r);
v[l-1].push_back(r-l+1-k);
}
}
for(int i=1;i<=n;i++)dis[i]=2147483647;//初始化
for(int i=0;i<n;i++)v[i].push_back(i+1),v[i].push_back(1),v[i+1].push_back(i),v[i+1].push_back(0);//加边
vis[0]=1;
q.push(0);
if(spfa())
{
for(int i=1;i<=n;i++)
cout<<(dis[i]>dis[i-1])<<' ';
}
return 0;
}