zoukankan      html  css  js  c++  java
  • 图论/主席树优化建图-小火车什么什么三维宇宙

    题目大意:给 (n (nle 100,000)) 个三元组,保证每个数每一维构成 ([1,n]) 的排列,定义大于表示一个数至少两维比另一个数大,求某个顺序比较之后可能是最大的数的数具体是哪些。

    大于不具有传递性。

    入度为 (0) 的点一定可以是最大值,只要从这个点开始,每次随便找一个其他点比较就行。

    如果有环,考虑最终让 (a_i) 作为最大值,只要从大于 (a_i)(a_k) 开始,与大于 (a_k)(a_t) 比较,得到当前最大值 (a_t) ,继续……最后再与 (a_i) 比较即可。

    所以环上任意点都可以是最大值。

    两个数不是 (a>b) 就是 (a<b) ,即两点间一定有边,所以缩点之后入度为 (0) 的强连通分量只有一个。

    枚举“至少两维”中是哪两维,然后连边。如果升序讨论 (x_i) ,则应连向 (y_t < x_i, x_t < x_i) 的数。第一个限制,对 (y) 开权值线段树。第二个限制,把线段树开成可持久化的,每次添加完边后,再新增一条从根节点到 (y_i) 号叶子节点,并从叶子连向对应数的路径。

    Tarjan 写错变量名调了半天 Orz 。

    #include <cstdio>
    #include <ctype.h>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    char *p1, *p2, buf[1 << 20];
    
    inline char gc()
    {
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++;
    }
    
    template<typename T>
    void rd(T &num)
    {
        char tt;
        bool flag = 0;
        while (!isdigit(tt = gc()) && tt != '-');
        if (tt == '-')
            num = 0, flag = 1;
        else
            num = tt - '0';
        while (isdigit(tt = gc()))
            num = num * 10 + tt - '0';
        if (flag)
            num = -num;
        return;
    }
    
    const int _N = 101000;
    const int _M = 13500000;
    
    typedef int lar[_M];
    
    int EC, FK, N, ST_cnt, Stamp, S_cnt, SCC;
    int B[_N], X[_N], Y[_N], Z[_N], Rt[_N];
    lar Nxt, Fst, V, Fk_nxt, Fk_fst, Fk_v, L, R, Low, Dfn, S, Bel, Ind, Q;
    bool Mk[_M];
    
    void ins_edge(int a, int b)
    {
    	if (!a || !b)
    		return;
        ++EC, Nxt[EC] = Fst[a], Fst[a] = EC, V[EC] = b;
        return;
    }
    
    void fuck_edge(int a, int b)
    {
        ++FK, Fk_nxt[FK] = Fk_fst[a], Fk_fst[a] = FK, Fk_v[FK] = b;
        return;
    }
    
    void ins_path(int &p, int &q, int l, int r, int num, int val)
    {
        p = ++ST_cnt;
        if (l == r) {
            ins_edge(p, num);
            return;
        }
        int mid = (l + r) >> 1;
        if (val <= mid)
            R[p] = R[q], ins_path(L[p], L[q], l, mid, num, val);
        else
            L[p] = L[q], ins_path(R[p], R[q], mid + 1, r, num, val);
        ins_edge(p, L[p]), ins_edge(p, R[p]);
        return;
    }
    
    void connect(int &p, int l, int r, int num, int s, int t)
    {
        if (s > t || !p)
            return;
        if (s <= l && r <= t) {
            ins_edge(num, p);
            return;
        }
        int mid = (l + r) >> 1;
        if (s <= mid)
            connect(L[p], l, mid, num, s, t);
        if (t > mid)
            connect(R[p], mid + 1, r, num, s, t);
        return;
    }
    
    void owo(int *x, int *y)
    {
        for (int i = 1; i <= N; ++i)
            B[x[i]] = i;
        Rt[0] = 0;
        for (int i = 1; i <= N; ++i) {
            connect(Rt[i - 1], 1, N, B[i], 1, y[B[i]] - 1);
            ins_path(Rt[i], Rt[i - 1], 1, N, B[i], y[B[i]]);
        }
        return;
    }
    
    void dfs(int p)
    {
        Low[p] = Dfn[p] = ++Stamp, Mk[p] = 1, S[++S_cnt] = p;
        for (int i = Fst[p]; i; i = Nxt[i]) {
            int &t = V[i];
            if (!Dfn[t])
                dfs(t), Low[p] = min(Low[p], Low[t]);
            else if (Mk[t])
                Low[p] = min(Low[p], Dfn[t]);
        }
        if (Low[p] != Dfn[p])
            return;
        int tmp;
        ++SCC;
        do {
            tmp = S[S_cnt--], Mk[tmp] = 0, Bel[tmp] = SCC;
        } while (tmp != p);
        return;
    }
    
    int main()
    {
        rd(N);
        for (int i = 1; i <= N; ++i)
            rd(X[i]), rd(Y[i]), rd(Z[i]);
        ST_cnt = N;
        owo(X, Y), owo(X, Z), owo(Y, Z);
        for (int i = 1; i <= ST_cnt; ++i)
            if (!Dfn[i])
                dfs(i);
        for (int i = 1; i <= ST_cnt; ++i)
            for (int j = Fst[i]; j; j = Nxt[j]) {
                int &t = V[j];
                if (Bel[i] != Bel[t])
                    fuck_edge(Bel[i], Bel[t]), ++Ind[Bel[t]];
            }
        for (int i = 1; i <= N; ++i)
            Mk[Bel[i]] = 1;
        
        int hd = 1, tl = 1, ans = -1;
        for (int i = 1; i <= SCC; ++i)
            if (!Ind[i])
                Q[tl++] = i;
        while (hd < tl) {
            int p = Q[hd++];
            if (Mk[p]) {
                ans = p;
                break;
            }
            for (int i = Fk_fst[p]; i; i = Fk_nxt[i]) {
                int &t = Fk_v[i];
                if (!--Ind[t])
                    Q[tl++] = t;
            }
        }
        for (int i = 1; i <= N; ++i)
            printf("%d
    ", Bel[i] == ans);
        return 0;
    }
    
  • 相关阅读:
    js入门之DOM
    js入门之字符串常用的方法
    js入门之内置数组对象 Array
    js入门之内置对象Date
    js入门之内置对象Math
    js入门之对象
    js入门之函数
    js入门之数组
    js入门第二篇之流程控制语句
    js入门第一篇
  • 原文地址:https://www.cnblogs.com/ghcred/p/10169022.html
Copyright © 2011-2022 走看看