专题 差分约束 + 优化建图

1.矩阵估价

 

 

 

 solution:这个题并不难,重要的是它代表了一种思想,即差分约束只能解决a-b>p的问题,但是我们通过对h,a,b取log,将乘除法转化为了加减法,这个思想非常重要,下面贴个码。

#include <bits/stdc++.h>

using namespace std;

struct node {
    int to, nxt;
    double len;
}e[1000000]; int n, m, x, y, vis[500005], head[500005], cnt[500005], tot, h[405][405]; double dis[500005];
inline void add_e(int u, int v, double w) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot; e[tot].len = w;}

bool spfa()
{
    queue <int> Q;
    for (int i = 0; i <= n + m; i++) dis[i] = 1e9; 
    memset(cnt, 0, sizeof cnt);
    memset(vis, 0, sizeof vis);
    Q.push(0);
    dis[0] = 0;
    while (!Q.empty())
    {
        int u = Q.front(); Q.pop();
        vis[u] = 0;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].to;
            if (dis[v] > dis[u] + e[i].len)
            {
                dis[v] = dis[u] + e[i].len;
                if (++cnt[v] > n + m) return 0;
                if (!vis[v]) vis[v] = 1, Q.push(v);
            }
        }
    } return 1;
}

void solve()
{
    memset(head, 0, sizeof head); tot = 0;
    scanf("%d%d%d%d", &n, &m, &x, &y);
    for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &h[i][j]);
    double xx = log2(x), yy = log2(y);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            double hh = log2(h[i][j]);
            add_e(i, j + n, hh - xx);
            add_e(j + n, i, yy - hh);
        }
    }
    for (int i = 1; i <= n + m; i++) add_e(0, i, 0);
    if (spfa()) puts("YES");
    else puts("NO");
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--) solve();    
}

2.最省路费

 

 

 solution:异或优化建图经典题目,大体的思路就是将i与(i ^ 1<<j)连边,边权为j*c来将边数优化到nlogn的级别,下面贴个码。

#pragma GCC optimize(3)

#include <bits/stdc++.h>

using namespace std;

typedef pair <int, int> P;

struct node {
    int to, nxt, len;
}e[8000005]; int head[4000005], tot, dis[4000005];
bool vis[4000005];
inline void add_e(int u, int v, int w) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot; e[tot].len = w;}

void dijkstra(int s)
{
    priority_queue <P, vector <P>, greater <P> > Q;
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0; Q.push(make_pair(0, s));
    while (!Q.empty())
    {
        int u = Q.top().second; Q.pop();
        if (vis[u]) continue; else vis[u] = 1;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].to;
            if (!vis[v] && dis[v] > dis[u] + e[i].len)
            {
                dis[v] = dis[u] + e[i].len;
                Q.push(make_pair(dis[v], v));
            }
        }
    }
}

char buf[1 << 22], *p1 = buf, *p2 = buf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)

template <class T>
inline void rd(T &a)
{
    char ch = getchar(); int x = 0, f = 1;
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    a = x * f;
}

int main()
{
    int n, m, c;
    rd(n), rd(m), rd(c);
    for (int i = 1, x, y, z; i <= m; i++)
    {
        rd(x), rd(y), rd(z);
        add_e(x, y, z);    
    } int s, t; rd(s), rd(t);
    for (int i = 0; i <= n; i++) for (int j = 1; j <= n; j <<= 1) if ((i ^ j) <= n) add_e(i, i ^ j, j * c);
    dijkstra(s); printf("%d", dis[t]);
}

3.遗留

 

 

 

 solution:线段树优化建图板题,不多说了,下面贴个码。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <ll, ll> P;

#define mid (Tree[q].l + Tree[q].r >> 1)

struct node {
    int l, r;
};
node Tree[3000005]; int cnt = 1, ls[3000005], rs[3000005];
ll num[3000005][2];

struct Edge {
    int to, nxt;
    ll len;
}e[3000005]; int head[3000005]; 
ll dis[3000005], tot, n, q, k, s;
bool vis[3000005];

inline void add_e(int u, int v, ll w) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot; e[tot].len = w;}

void Build(int q, int x, int y, int tp)
{
    Tree[q].l = x, Tree[q].r = y;
//    printf("%d %d %d %d\n", q, tp, Tree[q].l, Tree[q].r);
    if (x < y)
    {
        ls[q] = ++cnt;
        Build(ls[q], x, mid, tp); !tp ? add_e(q, ls[q], 0) : add_e(ls[q], q, 0); 
        rs[q] = ++cnt; 
        Build(rs[q], mid + 1, y, tp); !tp ? add_e(q, rs[q], 0) : add_e(rs[q], q, 0);
    }
    else num[x][tp] = cnt;
}

void modify1(int q, int v, int x, int y, int z)
{
    if (Tree[q].l > y || Tree[q].r < x) return;
    if (Tree[q].l >= x && Tree[q].r <= y)
    {
        add_e(num[v][1], q, z);
        return;
    }
    modify1(ls[q], v, x, y, z);
    modify1(rs[q], v, x, y, z);
}

void modify2(int q, int v, int x, int y, int z)
{
    if (Tree[q].l > y || Tree[q].r < x) return;
    if (Tree[q].l >= x && Tree[q].r <= y)
    {
        add_e(q, num[v][0], z);
        return;
    }
    modify2(ls[q], v, x, y, z);
    modify2(rs[q], v, x, y, z);
}

void dijkstra(int s)
{
    priority_queue <P, vector <P>, greater <P> > Q;
    memset(dis, 0x3f, sizeof dis); dis[s] = 0;
    Q.push(make_pair(0, s));
    while (!Q.empty())
    {
        ll u = Q.top().second; Q.pop();
        if (vis[u]) continue; vis[u] = 1;
        for (ll i = head[u]; i; i = e[i].nxt)
        {
            ll v = e[i].to;
            if (!vis[v] && dis[v] > dis[u] + e[i].len)
            {
                dis[v] = dis[u] + e[i].len;
                Q.push(make_pair(dis[v], v));
            }
        }
    }
}

main()
{
    scanf("%lld%lld%lld", &n, &q, &s);
    Build(1, 1, n, 0); k = ++cnt;
    Build(cnt, 1, n, 1);
    for (ll i = 1; i <= n; i++) add_e(num[i][0], num[i][1], 0), add_e(num[i][1], num[i][0], 0);
    for (ll i = 1, tp, x, y, z, l, r; i <= q; i++)
    {
        scanf("%lld", &tp);
        if (tp == 1) scanf("%lld%lld%lld", &x, &y, &z), add_e(num[x][1], num[y][0], z);
        if (tp == 2) scanf("%lld%lld%lld%lld", &x, &l, &r, &z), modify1(1, x, l, r, z);
        if (tp == 3) scanf("%lld%lld%lld%lld", &x, &l, &r, &z), modify2(k, x, l, r, z);
    } dijkstra(num[s][1]);
    for (ll i = 1; i <= n; i++) printf("%lld ", dis[num[i][0]] >= 0x3f3f3f3f3f3f3f ? -1 : dis[num[i][0]]);
//    for (ll i = 1; i <= cnt; i++)
//    {
//        for (ll j = head[i]; j; j = e[j].nxt)
//        {
//            printf("***%d %d %d %d\n", i, e[j].to, e[j].len, j);
//        }
//    }
}

 

posted @ 2021-07-02 16:13  Chasing-Dreams  阅读(94)  评论(0)    收藏  举报