【2020牛客多校第二场】I Interval
I 题 Interval
原题:
思路
打的时候一看有区间操作想都没想,就觉得肯定是特别nb的数据结构|dp,结果...打脸,都是前面一堆数学题搞我心态(强行甩锅)
才发现就是网络流(对偶图)的模板题😂 网络流能让你看出来就不会是网络流了
大概思想就是把一个区间(l,r)看成坐标上的点,每次操作就是在点与点之间连边,求最小割。
但是nm这么大肯定过不了,so套路就来了(建对偶图求最短路)
可以参考 洛谷的狼捉🐇 这题照理说应该比Interval更难(早知道就不用dinic水这题了)
补充:
以下都是自己yy,说的不对可以忽略,不喜勿喷
可能有些人总是很好奇源点,汇点要怎么连边确定(怎么一下左上全连,一下...)
我认为既然本质是你要切掉一些边,你就一定会有进边和出边,可以从哪进去就连源点,可以从哪出来就连汇点。
(但是一定要保证连接进边和出边的一条路可以把图'切断')
比如这题,画图后会发现上边连的是源点,右边是汇点,因为这样无论怎么走都可以把 点 (1,n)'切出来'虽然我还没试其他的连边方法
代码
不会有人对偶图会建成和我一样的吧,不会吧,不会吧🐶
#include<bits/stdc++.h>
using namespace std;
const int N = 502 * 502;
const long long inf = 0x3f3f3f3f3f3f3f3f;
int n, m, qx, zx;
long long dis[N];
bool use[N];
struct node
{
int link;
long long w;
bool operator < (const node &qq) const{
return qq.w < w;
}
};
vector<node> f[N];
priority_queue<node> q;
void add_edge(int u,int v,long long w)
{
f[u].push_back((node){v, w});
f[v].push_back((node){u, w});
}
void dij()
{
for (int i= qx; i <= zx;i++)
dis[i] = inf;
dis[qx] = 0;
q.push((node){qx,0});
while (!q.empty())
{
node temp = q.top();
q.pop();
if(use[temp.link])
continue;
use[temp.link] = 1;
for(auto i:f[temp.link])
{
if(dis[i.link]>=dis[temp.link]+i.w)
{
dis[i.link] = dis[temp.link] + i.w;
q.push((node){i.link,dis[i.link]});
}
}
}
}
int main()
{
scanf("%d %d", &n,&m);
qx = 0;
zx = n * n + 1;
for (int i = 1; i <= m;i++)
{
int a, b,d;
char c[4];
scanf("%d %d %s %d", &a, &b, c, &d);
if(c[0]=='L')
{
if(b==n)
{
add_edge((a - 1) * (n - 1) + b-1, zx,d);
}
else
{
add_edge((a - 1) * (n - 1) + b - 1, (a - 1) * (n - 1) + b,d);
}
}
else
{
if(a==1)
{
add_edge((a - 1) * (n - 1) + b - 1, qx, d);
}
else
{
add_edge((a - 1) * (n - 1) + b - 1, (a - 2)* (n - 1) + b - 1, d);
}
}
}
// for (int i = 1; i <= n * n;i++)
// {
// printf("i:%d\n", i);
// for(auto j:f[i])
// {
// printf("%d ", j.link);
// }
// printf("\n");
// }
dij();
if(dis[zx]!=inf)
printf("%lld\n", dis[zx]);
else
printf("-1\n");
return 0;
}
/*
*/
$道路千万条,点赞第一条;阅读不规范,笔者两行泪$