种酸奶

问题描述

小 L 喜欢喝酸奶,春天来了,小 L 想把酸奶种在地里,等到来年春暖花开,就能长出好多好多酸奶了
有 nn 个坑,小 L 给坑都编上号,从 11 号到 nn 号,每个坑最多种一瓶酸奶。
但是有一些限制形如 k,a,b,ck,a,b,c 。
若 kk 等于 11 ,则第 aa 号坑到第 bb 号坑最多种 cc 瓶酸奶。
若 kk 等于 22 ,则第 aa 号坑到第 bb 号坑最少种 cc 瓶酸奶。
若 kk 等于 33 ,则第 aa 号坑到第 bb 号坑必须种少于 cc 瓶酸奶。
若 kk 等于 44 ,则第 aa 号坑到第 bb 号坑必须种多于 cc 瓶酸奶。
若 kk 等于 55 ,则第 aa 号坑到第 bb 号坑必须种等于 cc 瓶酸奶。

问小 L 最多种多少瓶酸奶

输入格式

第一行两个整数 n,mn,m ,表示有 nn 个坑,有 mm 条限制。
1≤n,m≤10001\le n,m\le1000
接下来 mm 行,每行四个整数 k,a,b,ck,a,b,c
1≤k≤51\le k\le 5 , 1≤a≤b≤n1\le a\le b\le n , ∣c∣<=2000|c|<=2000

输出格式

输出一行,若有解则输出一个整数,表示答案
否则输出 impossible

样例输入

5 5
1 1 4 4
2 2 5 1
3 2 4 2
4 1 5 2
5 1 3 2

样例输出

3
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000000
typedef long long ll;
int n, m;
int k, a, b, c;

struct edge {
    int u, v, w, next;  //入点、出点、边权、下一条边的编号
    bool operator<(const edge& e) const {
        return w < e.w;
    }
} edges[MAXN];

int tot = 0;                 //当前边的总数
vector<int> head(MAXN, -1);  //储存每个节点的第一条边的编号,-1表示没有边

void addEdge(int u, int v, int w) {  //加一条边
    edges[tot].u = u, edges[tot].v = v, edges[tot].next = head[u], edges[tot].w = w;
    head[u] = tot++;
}
int dis[MAXN], vis[MAXN], cnt[MAXN];

bool spfa(int s) {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    memset(cnt, 0, sizeof(cnt));
    queue<int> q;
    // dis[0] = 0;
    dis[s] = 0;
    q.push(s);
    vis[s] = 1;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i != -1; i = edges[i].next) {
            int v = edges[i].v;
            if (dis[v] > dis[u] + edges[i].w) {
                dis[v] = dis[u] + edges[i].w;
                cnt[v] = cnt[u] + 1;
                if (cnt[v] >= n)
                    return false;  //有负环
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }  // 1、3、5可达但是这里没有让他们连起来

    return true;
}

int main() {
    // freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        scanf("%d%d%d%d", &k, &a, &b, &c);

        if (k == 1) {  //<=
            addEdge(a - 1, b, c);
        } else if (k == 2) {  //>=
            addEdge(b, a - 1, -c);
        } else if (k == 3) {  //<
            addEdge(a - 1, b, c - 1);
        } else if (k == 4) {  //>
            addEdge(b, a - 1, -c - 1);
        } else if (k == 5) {  //=
            addEdge(a - 1, b, c);
            addEdge(b, a - 1, -c);
        }
    }
    for (int i = 1; i <= n; ++i) {
        addEdge(i - 1, i, 1);
        addEdge(i, i - 1, 0);
    }
    if (spfa(0)) {
        printf("%d", dis[n]);
    } else {
        printf("impossible");
    }

    return 0;
}