题解:P7056 [NWRRC 2015] Insider's Information
前言
个人洛谷首黑,模拟赛 T4 未切。
简化题面:
一个
观察题面:
首先想一下简化版,假设每个约束条件为
现在重新考虑一下这道题,由于每个约束条件
算法设计:
得出填的顺序后,我们开始考虑怎么填数。我们发现如果对于序列,前缀确定,后缀确定,只有中间一段空余,我们可以很轻易的算出已经确定两个点的约束条件是否产生贡献。因此我们考虑从两端填到中间,对于要填的
1.
2.
以上两种统计方式,对于每一个约束条件,只会在填第二个数的时候统计一次,因此不会算重或算漏。每次我们比较当前
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
int read()
{
char c=getchar();
int f=1,x=0;
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^'0');
c=getchar();
}
return x*f;
}
void print(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int N=1e5+5;
int n,m,in[N],l,r,ans[N],pos[N];
queue<int> q;
struct node
{
int x,y,z;
}a[N];
bool b[N],vis[N];
vector<node> edge[N],mid[N];
void add(int u)
{
int vl=0,vr=0;
for(auto it=edge[u].begin();it!=edge[u].end();it++)
{
int x=(*it).x,y=(*it).y,z=(*it).z;
if(!pos[x]&&pos[y])
{
if(pos[y]<l) vr++;
else vl++;
}
}
for(auto it=mid[u].begin();it!=mid[u].end();it++)
{
int x=(*it).x,y=(*it).y,z=(*it).z;
if(!pos[x]&&pos[y])
{
if(pos[y]<l) vl++;
else vr++;
}
if(pos[x]&&!pos[y])
{
if(pos[x]<l) vl++;
else vr++;
}
}
if(vl>=vr) ans[l]=u,pos[u]=l,l++;
else ans[r]=u,pos[u]=r,r--;
}
int main()
{
n=read();
m=read();
l=1,r=n;
for(int i=1;i<=m;i++)
{
int x,y,z;
x=read();
y=read();
z=read();
in[y]+=2;
edge[x].push_back({y,z,i});
edge[z].push_back({y,x,i});
mid[y].push_back({x,z,i});
if(x>y) swap(x,y);
a[i].x=x;
a[i].y=y;
a[i].z=z;
}
for(int i=1;i<=n;i++)
if(!in[i]) q.push(i);
while(q.size())
{
int u=q.front();
q.pop();
add(u);
for(auto it=edge[u].begin();it!=edge[u].end();it++)
{
int x=(*it).x,y=(*it).y,z=(*it).z;
if(b[z]) continue;
in[x]-=2;
b[z]=true;
if(!in[x]) q.push(x);
}
}
for(int i=1;i<=n;i++)
{
print(ans[i]);
putchar(' ');
}
return 0;
}