FIG cf-786B shortest interval

https://www.cnblogs.com/31415926535x/p/11611801.html
chance to see this thing can be said is the first time I saw the title Graph Theory + data structures, and, this title code is very simple, details of the deal what it lacks is the main idea ,,, step by step derivation is very good ,,

cf-786 Legacy

cf-786 Legacy

I have done before drawing thesis topic just drawing, data structures, and never thought - something to do ,, segment tree

This question can be considered a classic example of the bar ,, ought to know is the kind of type will be made out of done ,,

Ideas analysis

Meaning of the questions is very simple, it is a simple graph ,, give some way to build graphs ,, however, and different from the past, to the side of past relationships are between the dots ,, this question to the way the interval ,, for example, u->[l, r]indicated that between u and all points in this section have an edge ,, because a point can also be viewed as a range of only their own ,, so we can unify this type of relationship as \ ([L_1, R_1] -> [L_2, R_2] \) ,,

The method is easy to think of a direct up two for each side ,, ,, built a very young age data no problem ,,, but when n is large ,, obviously build Figure complexity is probably \ (O (n ^ 2m) \) so that regardless of seeking the shortest path on the bombing ,,,

An optimization method we add a point in front of this section ,, between these two sections (the section becomes) and a rear section (referred to the section) and have at this point \ (P \) is connected, , that is, \ (\ forall u \ in [ l_1, r_1]: addedge (u, p, w) \) and \ (\ forall v \ in [ l_2, r_2]: addedge (p, v, 0) \) ( \ ([L_1, R_1] -_ U> P-_0> [L_2, R_2] \) ) like this can be built to reduce the complexity of FIG ,, is a dimension \ (O (2nm) \) ,, but such still high ,,

This time map building is built linear map linear way ,, == + range segment tree? ? ! ! ,, This is what I do most of a valuable approach to the study of this question ,, after the fall of the one-dimensional, although linear map building ,, ,, but still a lot of points and segment tree can rarely happens the sub-interval to represent the original range ,,, if the interval represented by each line segment tree as a point ,, then we can use to build a small dot map ,,, so that you can be above n times of map building to go down ,,,

So then the question becomes how to handle the tree line ,,

We need two ,, a segment tree as the tree, the other one as a tree ,,

Firstly, our aim is to represent the range with a small amount of the original great range to achieve with very little point to represent all points of the original ,, optimization problems solved with tree line ,, But how correct representation of the original the point of it all ,,,

线段树的每一个节点表示一个区间,,这个节点可以表示他下面的所有点,,也就是说,,我们可以从上向下的看,,定义选择了一个节点,,就选择了下面的所有点,,,按照这个思想,入树中的一个节点要向其儿子连一条指向儿子的有向边,,也就是说,,入树中所有的边指向下,,用 down 表示

同理,,对于出树,,我们要保证在一个节点要能表示所有的点,,于是就是一个节点下的所有节点都要指向它,,,这样看这棵树就是一个向上的树,,用 up 表示,,

这个样子的:

这样最后在这样初始图加上题目给的一些条件的边跑一边最短路就可以了,,

加上题目的边后的图大致是这样的:

实际上,,这里的线段树的作用只是一个建树和查询其子区间的作用,,这个思想有点像是分块,,,只要能找到一个合理的区间分块,,用一些合理的、数量少的区间表示原来的区间,,就能达到减少点数的作用,,,,而线段树恰好是一个熟悉的、好操作的区间划分模型,,所以很多人都对于 区间图的最短路问题都是套一个线段树的板子,,

回到这道题,,题目的加边方式只有 点对区间 和 区间对点 两种,,所以我们可以先预留出那n个点,,可以想象成放在这两棵树之间的一排点(不用再将两棵树的叶子节点相连,,),,,

然后再处理出出树、入树的边后,,对于 u->[l, r]u->v 的边,,从点 u 向入树的符合条件的节点连边即可,,因为之前说的入树保证了每一个节点是可以到其下面的叶子节点的,,所以我们这样连边就相当于是点 u 向区间的每一个点连边,,,

同理对于 [l, r]->u 这样的边,,我们将入树的对应的节点和点 u 相连,,这样就保证入树中这个区间下的叶子节点可以通过这些区间到点 u ,,这样也满足了题意的同时减少的连边的复杂度,,,

最后跑最短路,,前n个点的 dis[i] 即为源图的那些点的最短路,,,

于是我们通过加点减边的方式减小了建图的时间复杂度,,

关于处理出树、入树的操作,,也就是线段树的建树过程,,其实线段树并不维护任何信息,,我们只是用它自己每个节点表示一个区间这个自身的性质,,所以为了建图,,,我们需要对每一个节点连一些边,,,也就是用一个 id[rt] 标记一下每一个节点的标号即可,,,

最后的代码:

#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 1e6 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;

struct Dijkstra
{
    struct edge
    {
        int to, nxt; ll w;
    }edge[maxm];
    int tot, head[maxm];
    void init()
    {
        tot = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int u, int v, ll w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    struct node
    {
        int v; ll w;
        node(){}
        node(int _v, ll _w):v(_v), w(_w){}
        const bool operator<(const node &r)const
        {
            return w > r.w;
        }        
    };
    bool vis[maxn];
    ll dis[maxn];
    priority_queue<node> pq;
    void dijkstra(int s, int n)
    {
        memset(vis, false, sizeof vis);
        memset(dis, inf, sizeof dis);
        while(!pq.empty())pq.pop();
        pq.push(node(s, 0));
        dis[s] = 0;
        node t;
        int u;
        while(!pq.empty())
        {
            t = pq.top(); pq.pop();
            u = t.v;
            if(vis[u])continue;
            vis[u] = true;
            for(int i = head[u]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].to;
                ll w = edge[i].w;
                if(dis[v] > t.w + w)
                {
                    dis[v] = t.w + w;
                    pq.push(node(v, dis[v]));
                }
            }
        }
    }
    void print(int n)
    {
        for(int i = 1; i <= n; ++i)cout << (dis[i] == linf ? -1 : dis[i]) << " ";cout << endl;
    }
}dijkstra;

int cnt;
struct segmentTree
{
    int id[maxn];           // 节点标记数组,,记录线段树中每一个节点的标号,,从 n+1 开始,,前面的n个是原来的点
    void build(int rt, int l, int r, bool flag)     // 建树(建图,,flag == false 表示是一棵入树,边向下,节点指向儿子
    {
        id[rt] = ++cnt;
        if(l == r)
        {
            int u = id[rt];
            int v = l;
            if(flag)swap(u, v);
            dijkstra.addedge(u, v, 0);
            return;
        }
        int mid = l + r >> 1;
        build(rt << 1, l, mid, flag);
        build(rt << 1 | 1, mid + 1, r, flag);
        // pushup
        int u = id[rt];
        int v = id[rt << 1];
        if(flag)swap(u, v);
        dijkstra.addedge(u, v, 0);
        u = id[rt];
        v = id[rt << 1 | 1];
        if(flag)swap(u, v);
        dijkstra.addedge(u, v, 0);
        return;
    }
    void addedge(int rt, int l, int r, int U, int L, int R, ll w, bool flag)    // flag == false 表示 u->[l, r] ,,
    {
        if(l > R || L > r)return;
        if(L <= l && r <= R)
        {
            int u = U;
            int v = id[rt];
            if(flag)swap(u, v);
            dijkstra.addedge(u, v, w);
            return;
        }
        int mid = l + r >> 1;
        if(L <= mid)addedge(rt << 1, l, mid, U, L, R, w, flag);
        if(R >  mid)addedge(rt << 1 | 1, mid + 1, r, U, L, R, w, flag);
        return;
    }
}down, up;

int main()
{
    // double pp = clock();
    // freopen("233.in", "r", stdin);
    // freopen("233.out", "w", stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    int n, q, s;
    cin >> n >> q >> s;
    cnt = n;                // 出树、入树等的辅助点的标记从n+1开始
    dijkstra.init();
    down.build(1, 1, n, false);
    up.build(1, 1, n, true);
    int t, u, v, w, l, r;
    while(q--)
    {
        cin >> t;
        if(t == 1)
        {
            cin >> u >> v >> w;
            l = r = v;
            t = 2;
        }
        else 
            cin >> u >> l >> r >> w;
        
        if(t == 2)
            down.addedge(1, 1, n, u, l, r, w, false);   // u -> [l, r]
        else
            up.addedge(1, 1, n, u, l, r, w, true);      // [l, r] -> u
    }
    dijkstra.dijkstra(s, cnt);
    dijkstra.print(n);

    // cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
    return 0;
}

以上的一些内容和图片参考这个dalao的博客

最后的AC代码的大致思路是参考葫芦爷大佬的板子

hdu-5361In Touch

hdu-5361In Touch

差不多的题,,貌似解法有很多,,如果用这种方法来解的话,,只用一棵入树就行了,,,还有可能得改一改写的姿势,,,(重载w爆int一晚上没看出来的怕不是只有我一个了吧,,,emmmm

AC_1

#include <bits/stdc++.h>
// #include <iostream>
// #include <queue>
// #include <cstring>

#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;

inline int read()   //快读
{
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))
        ch=getchar();
    while(isdigit(ch))
        ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int n;
struct edge
{
    int to, nxt;
    ll w;
}edge[maxm];
int tot, head[maxn << 3];
void init(int n)
{
    tot = 0;
    for(int i = 0; i <= n; ++i)head[i] = -1;
}
void ADDEDGE(int u, int v, ll w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
struct node
{
    int v; 
    ll w;
    node(){};
    node(int _v, ll _w): v(_v), w(_w){};
    const bool operator<(const node &r)const{
        return w > r.w;
    }
}tmp;
bool vis[maxn << 3];
ll dis[maxn << 3];
priority_queue<node> pq;
void dijkstra(int s, int n)
{
    for(int i = 0; i <= n; ++i)dis[i] = linf;
    for(int i = 0; i <= n; ++i)vis[i] = false;
    while(!pq.empty())pq.pop();
    pq.push(node(s, 0));
    dis[s] = 0;
    while(!pq.empty())
    {
        tmp = pq.top(); pq.pop();
        if(vis[tmp.v])continue;
        vis[tmp.v] = true;
        for(int i = head[tmp.v]; ~i; i = edge[i].nxt)
        {
            int v = edge[i].to;
            if(dis[v] > dis[tmp.v] + edge[i].w)
            {
                dis[v] = dis[tmp.v] + edge[i].w;
                pq.push(node(v, dis[v]));
            }
        }
    }
}

int cnt;
void build(int rt, int l, int r)
{
    if(l == r)
    {
        cnt = max(cnt, rt + n);
        ADDEDGE(rt + n, l, 0);
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    ADDEDGE(rt + n, (rt << 1) + n, 0);
    ADDEDGE(rt + n, (rt << 1 | 1) + n, 0);
}
int L, R, W, U;
void addedge(int rt, int l, int r)
{
    if(L > r || l > R)return;
    if(L <= l && r <= R)
    {
        ADDEDGE(U, rt + n, W);
        return;
    }
    int mid = l + r >> 1;
    if(L <= mid)addedge(rt << 1, l, mid);
    if(R >  mid)addedge(rt << 1 | 1, mid + 1, r);
}
int l[maxn], r[maxn], c[maxn];
int main()
{
    // double pp = clock();
    // freopen("233.in", "r", stdin);
    // freopen("233.out", "w", stdout);
    // ios_base::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);

    // int t; cin >> t;
    // int t; scanf("%d", &t);
    int t; t = read();
    while(t--)
    {
        // cin >> n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)l[i] = read();
        for(int i = 1; i <= n; ++i)r[i] = read();
        for(int i = 1; i <= n; ++i)c[i] = read();
        init(n << 3);
        cnt = 0;
        build(1, 1, n);
        for(int i = 1; i <= n; ++i)
        {
            U = i;
            L = i + l[i]; R = i + r[i]; W = c[i];
            addedge(1, 1, n);
            L = i - r[i]; R = i - l[i];
            addedge(1, 1, n);
        }
        dijkstra(1, cnt);
        printf("0");
        for(int i = 2; i <= n; ++i)
            printf(" %lld", (dis[i] == linf ? -1 : dis[i]));
        puts("");
    }

    // cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
    return 0;
}

AC_2

(不加快读也没事,,,就是不能memset,,,卡memset好恶心,,,,

#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;

inline int read()   //快读
{
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))
        ch=getchar();
    while(isdigit(ch))
        ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
struct Dijkstra
{
    struct edge
    {
        int to, nxt;
        ll w;
    }edge[maxm];
    int tot, head[maxn << 3];
    void init(int n)
    {
        tot = 0;
        // memset(head, -1, sizeof head);
        for(int i = 0; i <= n; ++i)head[i] = -1;
    }
    void addedge(int u, int v, ll w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    struct node
    {
        int v; ll w;
        node(){}
        node(int _v, ll _w):v(_v), w(_w){}
        const bool operator<(const node &r)const
        {
            return w > r.w;
        }
    };
    bool vis[maxn << 3];
    ll dis[maxn << 3];
    priority_queue<node> pq;
    void dijkstra(int s, int n)
    {
        // memset(vis, false, sizeof vis);
        // memset(dis, inf, sizeof dis);
        for(int i = 0; i <= n; ++i)vis[i] = false;
        for(int i = 0; i <= n; ++i)dis[i] = linf;
        while(!pq.empty())pq.pop();
        pq.push(node(s, 0));
        dis[s] = 0;
        node t; int u;
        while(!pq.empty())
        {
            t = pq.top(); pq.pop();
            u = t.v;
            if(vis[u])continue;
            vis[u] = true;
            for(int i = head[u]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].to;
                ll w = edge[i].w;
                if(dis[v] > t.w + w)
                {
                    dis[v] = t.w + w;
                    pq.push(node(v, dis[v]));
                }
            }
        }
    }
    void print(int n)
    {
        printf("0");
        for(int i = 2; i <= n; ++i)printf(" %lld", (dis[i] == linf ? -1 : dis[i]));
        puts("");
    }
}dijkstra;

int cnt;
struct segmentTree
{
    int id[maxn << 3];
    void build(int rt, int l, int r, bool flag)
    {
        id[rt] = ++cnt;
        if(l == r)
        {
            int u = id[rt];
            int v = l; 
            if(flag)swap(u, v);
            dijkstra.addedge(u, v, 0);
            return;
        }
        int mid = l + r >> 1;
        build(rt << 1, l, mid, flag);
        build(rt << 1 | 1, mid + 1, r, flag);
        int u = id[rt];
        int v = id[rt << 1];
        if(flag)swap(u, v);
        dijkstra.addedge(u, v, 0);
        u = id[rt];
        v = id[rt << 1 | 1];
        if(flag)swap(u, v);
        dijkstra.addedge(u, v, 0);
        return;
    }
    void addedge(int rt, int l, int r, int U, int L, int R, ll w, bool flag)
    {
        if(L > r || R < l)return;
        if(L <= l && r <= R)
        {
            int u = U;
            int v = id[rt];
            if(flag)swap(u, v);
            dijkstra.addedge(u, v, w);
            return;
        }
        int mid = l + r >> 1;
        if(L <= mid)addedge(rt << 1, l, mid, U, L, R, w, flag);
        if(R >  mid)addedge(rt << 1 | 1, mid + 1, r, U, L, R, w, flag);
        return;
    }
}down; //, up;

int l[maxn], r[maxn], c[maxn];
int main()
{
    // double pp = clock();
    // freopen("233.in", "r", stdin);
    // freopen("233.out", "w", stdout);
    // ios_base::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);

    int t; t = read();
    while(t--)
    {
        int n; n = read();
        for(int i = 1; i <= n; ++i)l[i] = read();
        for(int i = 1; i <= n; ++i)r[i] = read();
        for(int i = 1; i <= n; ++i)c[i] = read();
        cnt = n;
        dijkstra.init(n << 3);
        down.build(1, 1, n, false);
        // up.build(1, 1, n, true);
        for(int i = 1; i <= n; ++i)
        {
            down.addedge(1, 1, n, i, l[i] + i, r[i] + i, c[i], false);
            down.addedge(1, 1, n, i, max(1, i - r[i]), max(1, i - l[i]), c[i], false);
        }
        dijkstra.dijkstra(1, cnt);
        dijkstra.print(n);
    }

    // cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
    return 0;
}

(end)

Guess you like

Origin www.cnblogs.com/31415926535x/p/11611801.html