zoukankan      html  css  js  c++  java
  • 【LOJ】#2270. 「SDOI2017」天才黑客

    题解

    显然要记录每个点来的状态,这样会扩充出点度的平方条边,就gg了

    删掉所有的点,把每个边拆成两个点,连一条边权为c

    这个时候我们考虑对于原先的每个点,将所有与其相连边所需要的节点(不管是进入还是出去)建一棵虚树,然后用线段树优化建图,优化方法是枚举每个lca,然后将lca的每个子树和其他子树连一条长度为lca深度的边,也就是dfs序上连续的一段

    进到这个点的边拆出来的点和负责出去的线段树的子节点连一条边
    负责进来的线段树向这个点出去的节点连一条边
    跑最短路就行

    然后就做完了……
    写的我真累= =

    我非常好奇到底如何能只写3.xK????
    update:貌似有更清奇的写法不用线段树orzzzzz

    代码

    (7.6K的sd代码,不看也罢)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define MAXN 200005
    #define MAXK 80005
    typedef long long int64;
    using namespace std;
    template<class T>
    void read(T &res) {
    	res = 0;char c = getchar();T f = 1;
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		res = res * 10 + c - '0';
    		c = getchar();
    	}
    	res *= f;
    }
    template<class T>
    void out(T x) {
    	if(x < 0) {x = -x;putchar('-');}
    	if(x >= 10) {
    		out(x / 10);
    	}
    	putchar('0' + x % 10);
    }
    int N,M,K;
    priority_queue<pair<int64,int> > Q;
    namespace Tree {
        struct node {
            int next,to;
        }E[MAXK * 2];
        int head[MAXK],sumE,dfn[MAXK],idx,dep[MAXK];
        int st[MAXK * 2][17],len[MAXK * 2],pos[MAXK],tot;
        void add(int u,int v) {
            E[++sumE].next = head[u];
            E[sumE].to = v;
            head[u] = sumE;
        }
        int min_dep(int a,int b) {
            return dep[a] < dep[b] ? a : b;
        }
        int lca(int a,int b) {
            a = pos[a];b = pos[b];
            if(a > b) swap(a,b);
            int l = len[b - a + 1];
            return min_dep(st[a][l],st[b - (1 << l) + 1][l]);
        }
        void dfs(int u,int fa) {
            dfn[u] = ++idx;
            st[++tot][0] = u;pos[u] = tot;dep[u] = dep[fa] + 1;
            for(int i = head[u] ; i ; i = E[i].next) {
                int v = E[i].to;
                if(v != fa) {
                    dfs(v,u);
                    st[++tot][0] = u;
                }
            }
        }
        void Init() {
            sumE = 0;memset(head,0,sizeof(head));idx = 0;
            memset(st,0,sizeof(st));
            int u,v,w;
            for(int i = 1 ; i < K ; ++i) {
                read(u);read(v);read(w);
                add(u,v);
            }
            idx = 0;tot = 0;
            dfs(1,0);
            for(int i = 2 ; i <= tot ; ++i) len[i] = len[i / 2] + 1;
            for(int j = 1 ; j <= 16 ; ++j) {
                for(int i = 1 ; i <= tot ; ++i) {
                    st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
                }
            }
        }
    }
    namespace Graph {
        struct node {
            int next,to;
            int64 val;
        }E[4000005];
        int head[1000005],sumE,pos[1000005],Ncnt,S;
        vector<int> vec[MAXN][2];
        int Line[200005],tot,sta[MAXK],top,faAux[MAXK],siz[MAXK],d[MAXK],pz[2][MAXK],tr[2][MAXK * 8];
        int64 dis[1000005];
        bool vis[1000005];
        bool cmp(int a,int b) {
            return Tree::dfn[a] < Tree::dfn[b];
        }
        void add(int u,int v,int64 c) {
            E[++sumE].to = v;
            E[sumE].next = head[u];
            E[sumE].val = c;
            head[u] = sumE;
        }
        void Init() {
            sumE = 0;Ncnt = 0;memset(head,0,sizeof(head));
            for(int i = 1 ; i <= N ; ++i) {vec[i][0].clear();vec[i][1].clear();}
            int a,b,d;
            int64 c;
            for(int i = 1 ; i <= M ; ++i) {
                read(a);read(b);read(c);read(d);
                pos[Ncnt + 1] = d;pos[Ncnt + 2] = d;
                vec[a][1].pb(Ncnt + 1);vec[b][0].pb(Ncnt + 2);
                add(Ncnt + 1,Ncnt + 2,c);
                Ncnt += 2;
            }
            S = ++Ncnt;
            pos[S] = 1;vec[1][0].pb(S);
        }
        void Build_SegmentTree(int id,int u,int L,int R) {
            tr[id][u] = ++Ncnt;
            if(L == R) {pz[id][Line[R]] = Ncnt;return;}
            int mid = (L + R) >> 1;
            Build_SegmentTree(id,u << 1,L,mid);
            Build_SegmentTree(id,u << 1 | 1,mid + 1,R);
            if(!id) {add(tr[id][u << 1],tr[id][u],0);add(tr[id][u << 1 | 1],tr[id][u],0);}
            else {add(tr[id][u],tr[id][u << 1],0);add(tr[id][u],tr[id][u << 1 | 1],0);}
        }
        void Add_Edge(int id,int u,int L,int R,int l,int r,int v,int64 c) {
            if(L == l && R == r) {
                if(!id) {add(tr[id][u],v,c);}
                else {add(v,tr[id][u],c);}
                return;
            }
            int mid = (L + R) >> 1;
            if(r <= mid) Add_Edge(id,u << 1,L,mid,l,r,v,c);
            else if(l > mid) Add_Edge(id,u << 1 | 1,mid + 1,R,l,r,v,c);
            else {Add_Edge(id,u << 1,L,mid,l,mid,v,c);Add_Edge(id,u << 1 | 1,mid + 1,R,mid + 1,r,v,c);}
        }
        void Build_AuxTree() {
            top = 0;
            sta[++top] = Line[1];faAux[Line[1]] = 0;
            int c = tot;
            for(int i = 2 ; i <= c ; ++i) {
                int f = Tree::lca(sta[top],Line[i]);
                while(top >= 1 && Tree::dep[sta[top]] > Tree::dep[f]) {
                    if(top == 1 || Tree::dep[sta[top - 1]] <= Tree::dep[f]) {
                        faAux[sta[top]] = f;
                    }
                    --top;
                }
                if(f != sta[top]) {
                    faAux[f] = sta[top];
                    sta[++top] = f;
                    Line[++tot] = f;
                }
                sta[++top] = Line[i];
                faAux[Line[i]] = f;
            }
            sort(Line + 1,Line + tot + 1,cmp);
            for(int i = 1 ; i <= tot ; ++i) siz[Line[i]] = 1;
            for(int i = tot ; i >= 1 ; --i) {
                siz[faAux[Line[i]]] += siz[Line[i]];
                d[Line[i]] = i;
            }
            Build_SegmentTree(0,1,1,tot);
            Build_SegmentTree(1,1,1,tot);
            for(int i = 1 ; i <= tot ; ++i) {
                int u = Line[i];
                ++Ncnt;
                Add_Edge(0,1,1,tot,i,i,Ncnt,Tree::dep[u] - 1);
                Add_Edge(1,1,1,tot,i,i + siz[u] - 1,Ncnt,0);
                int f = faAux[u];
                if(f) {
                    ++Ncnt;
                    Add_Edge(0,1,1,tot,i,i + siz[u] - 1,Ncnt,Tree::dep[f] - 1);
                    if(d[f] <= i - 1)
                        Add_Edge(1,1,1,tot,d[f],i - 1,Ncnt,0);
                    if(d[f] + siz[f] - 1 >= i + siz[u])
                        Add_Edge(1,1,1,tot,i + siz[u],d[f] + siz[f] - 1,Ncnt,0);
                }
            }
        }
        void Build_Graph() {
            for(int i = 1 ; i <= N ; ++i) {
                tot = 0;
                for(int k = 0 ; k <= 1 ; ++k) {
                    for(int j = 0 ; j < vec[i][k].size() ; ++j) {
                        Line[++tot] = pos[vec[i][k][j]];
                    }
                }
                sort(Line + 1,Line + tot + 1);
                tot = unique(Line + 1,Line + tot + 1) - Line - 1;
                sort(Line + 1,Line + tot + 1,cmp);
    
                Build_AuxTree();
                for(int k = 0 ; k <= 1 ; ++k) {
                    for(int j = 0 ; j < vec[i][k].size() ; ++j) {
                        int t = vec[i][k][j];
                        if(!k) add(t,pz[k][pos[t]],0);
                        else add(pz[k][pos[t]],t,0);
                    }
                }
            }
        }
    
        void Dijkstra() {
            for(int i = 1 ; i <= Ncnt ; ++i) {
                dis[i] = 1e16;vis[i] = 0;
            }
            dis[S] = 0;
            Q.push(mp(-dis[S],S));
            while(!Q.empty()) {
                pair<int64,int> now = Q.top();Q.pop();
                int u = now.se;
                if(vis[u]) continue;
                vis[u] = 1;
                for(int i = head[u] ; i; i = E[i].next) {
                    int v = E[i].to;
                    if(dis[v] > dis[u] + E[i].val) {
                        dis[v] = dis[u] + E[i].val;
                        Q.push(mp(-dis[v],v));
                    }
                }
            }
        }
        void Print() {
            for(int i = 2 ; i <= N ; ++i) {
                int64 ans = 1e16;
                for(int j = 0 ; j < vec[i][0].size() ; ++j) ans = min(ans,dis[vec[i][0][j]]);
                out(ans);enter;
            }
        }
    }
    void Solve() {
        read(N);read(M);read(K);
        Graph::Init();
        Tree::Init();
        Graph::Build_Graph();
        Graph::Dijkstra();
        Graph::Print();
    }
    int main() {
    #ifdef ivorysi
    	freopen("f1.in","r",stdin);
    #endif
        int T;
        read(T);
        while(T--) Solve();
    	return 0;
    }
    

    md我zz吧
    我代码是别人的两倍,运行时间也是别人的两倍啊
    我附加点为什么最后都建到1000000去了,不应该啊,然后还0.5s?是LOJ的评测机扩充了我的想象力吗

    好写???
    没觉得好写啊???
    我觉得刷新了我难写的上限啊???
    思路和细节写的比NOI2018D2T2还累啊,我代码能力难道真的退化了???

  • 相关阅读:
    C# 图片存入SQL Server数据库
    C#如何将Build成功的程序集Copy到上一层目录
    JavaScript中JSON字符串和JSON对象相互转化
    如何将C#对象转化为JSON字符串
    SQL的常用语句
    NHibernate的使用
    如何配置Spring的XML文件及使用
    TRIGGER的使用(修改SP自动触发)
    iOS UIButton上下排列(上图下文)
    将.c .h文件打包成静态库 .a .so
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9740693.html
Copyright © 2011-2022 走看看