• %你赛第2期题解


    T1自由之翼 的 题解

    这道题是Kirito_Rivaille神仙出的

    分析

    这么智障的题,就不讲了。
    再做不出来,你们真是SLZ。

    CODE:

    自己YY一下不就有了,不发了。
    

    T2虫群之心 的 题解

    这道题是wyxdrqc大佬出的

    但是wyxdrqc比较懒,不想写题解,那就让他讲吧。
    不发了。

    T3虚空之遗 的 题解

    很明显的最短路啊。这是窝这个蒟蒻出的qwq。

    分析:

    看完题后,我们发现这道题的建图很奇怪,不是常规的从一点到另一点的连边,有的边是从区间到区间的,这个时候点操作就不是很好办。那好像不太好建图,没法跑图上算法。

    但其实是可以的,有一种叫 线段树优化建图 的东西可以实现图上区间连边操作。

    线段树优化建图:

    我知道你想说这和线段树有什么关系,但其实你这样想,我们有2棵线段树:入与出。(出表示从这里出发,入表示进到了这个点)。
    于是每条区间加边就可以转为log级别。

    具体可以么干:

    建两棵线段树。
    第一棵线段树的儿子向父亲连边,第二棵线段树的父亲向儿子连边。
    第二棵线段的儿子节点向第一棵线段树的儿子节点连边,
    每次连边的时候新建两个节点。
    从第一棵线段树对应的区间向第一个点连边。
    从第一个点向第二个点连边。
    从第二个点向第二棵线段树对应的区间连边。
    把第一棵线段树对应的节点当做每个点的起点。

    真正的Solution:

    窝前面说了这么多,你们难道就不考虑下线段树优化建图吗?
    所以,我们考虑下怎么用线段树优化建图来求解。
    建立两颗线段树,A线段树每个节点和其父亲节点之间有一条边,边权为0
    B线段树每个节点和其两个儿子节点之间有一条边,边权为0
    B线段树的每个叶节点和A线段树的每个叶节点之间有一条边,边权为0
    对于每一个 $ op1 $ 的操作,我们建一条从A线段树叶节点到B线段树叶节点的边,边权为w
    对于每一个 $ op
    2 $ 的操作,我们建一条从A线段树叶节点到B线段树区间节点的边,边权为w 因为B线段树是从上向下建,那么就相当于u节点可以到B区间节点的区间内的每一个节点。
    对于每一个 $ op==3 $ 的操作,我们建一条从A线段树区间节点到B线段树叶子节点的边,边权为w 因为A线段树我们是从下向上建,那么就相当于A区间节点内的每一个点都可以到达B点的叶子节点。

    最后跑一个最短路就可以了

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
     
    using namespace std;
    
    #define lson (i<<1)
    #define rson (i<<1|1)
    #define ll long long
    
    typedef pair< ll, int > pii;
    
    const ll inf =1e18+5;
    const int N =1e5+5;
     
    struct node {
        int l,r;
        int num;
    }ta[N<<2],tb[N<<2];
     
    int pa[N],pb[N];
    struct node1 {
        ll w;
        int v;
        node1(ll _w,int _v):w(_w),v(_v){}
    };
    
    vector< node1 >ve[N*8];
    int vis[N*8],tot;
    ll dis[N*8],w;
    int opt,l,r,u,v;
    int n,m,q,s;
     
    void builda(int i,int l,int r) {// 自下向上建边
        ta[i].l = l; 
        ta[i].r=r; 
        ta[i].num = ++tot;
        if(ta[i].l == ta[i].r) {
            pa[l] = ta[i].num;
            return ;
        }
        int mid = (ta[i].l + ta[i].r) >> 1;
        builda(lson , l , mid);
        builda(rson , mid + 1 , r);
        ve[ta[lson].num].push_back(node1(0,ta[i].num));
        ve[ta[rson].num].push_back(node1(0,ta[i].num));
    }
     
    void updatea(int i,int l,int r,int num,ll w) {
        if(ta[i].l == l && ta[i].r == r) { // cong l,r dao u
            ve[ta[i].num].push_back(node1(w,num)); // 从a线段树的区间向b线段树的底部建一条边
            return ;
        }
        int mid = (ta[i].l + ta[i].r) >> 1;
        if(r <= mid) updatea(lson,l,r,num,w);
        else if(l > mid) updatea(rson,l,r,num,w);
        else {
            updatea(lson,l,mid,num,w);
            updatea(rson,mid+1,r,num,w);
        }
    }
    void buildb(int i,int l,int r) { // 自上向下建边
        tb[i].l = l; 
        tb[i].r = r; 
        tb[i].num = ++tot;
        if(tb[i].l == tb[i].r) {
            pb[l] = tb[i].num;
            ve[tb[i].num].push_back(node1(0,pa[l]));  
            //从b线段树的底部向a线段树的底部建一条0遍表示两个点在逻辑上是一个点
            return ;
        }
        int mid = (tb[i].l + tb[i].r) >> 1;
        buildb(lson , l , mid);
        buildb(rson , mid + 1 , r);
        ve[tb[i].num].push_back(node1(0,tb[lson].num));
        ve[tb[i].num].push_back(node1(0,tb[rson].num));
    }
     
    void updateb(int i,int l,int r,int num,ll w) {
        if(tb[i].l == l && tb[i].r == r) {
            ve[num].push_back(node1(w,tb[i].num)); 
            // 从a线段树的底部向b线段树的 区间建一条边
            return ;
        }
        int mid = (tb[i].l + tb[i].r) >> 1;
        if(r <= mid) updateb(lson,l,r,num,w);
        else if(l > mid) updateb(rson,l,r,num,w);
        else {
            updateb(lson,l,mid,num,w);
            updateb(rson,mid+1,r,num,w);
        }
    }
    void dij(int st) {
        memset(vis,0,sizeof(vis));
        for(int i = 0 ; i <= 8 * n ; i++) 
            dis[i]=inf;
        dis[st] = 0;
        pii tmp;
        priority_queue< pii,vector<pii> ,greater<pii> >q;
        q.push(pii(0,st));
        int u,v;
        while(!q.empty() ) {
            tmp=q.top(); 
            q.pop();
            u = tmp.second;
            if(tmp.first > dis[u]) continue;
            vis[u] = 1;
            //cout<<"****** u "<<u<<" "<<dis[u]<<endl;
            for(int i = 0 ; i < ve[u].size() ; i++) {
                v = ve[u][i].v;
                if(vis[v]) continue;
                if(dis[v] > dis[u] + ve[u][i].w){
                    dis[v] = dis[u] + ve[u][i].w;
                    q.push(pii(dis[v],v));
                }
            }
     
        }
        for(int i = 1 ; i <= n ; i++) {
            if(dis[pa[i]] != inf) {
                printf("%lld ",dis[pa[i] ]);
            }
            else printf("-1 ");
        } 
        return ;
    }
     
    int main() {
        scanf("%d %d %d",&n,&m,&s);
        int rta = 1;
        builda(1,1,n);
        int rtb = 1;
        //cout<<"rtb "<<rtb<<endl;
        buildb(rtb,1,n);
        while(m--) {
            scanf("%d",&opt);
            if(opt == 1) { 
                scanf("%d %d %lld",&u,&v,&w);
                ve[pa[u]].push_back(node1(w,pb[v]));
            }
            else if(opt == 2) { // 从 u 到 l,r
                scanf("%d %d %d %lld",&u,&l,&r,&w);
                updateb(rtb,l,r,pa[u],w);
            }
            else if(opt == 3) {  // 从 l,r到u
                scanf("%d %d %d %lld",&u,&l,&r,&w);
                updatea(rta,l,r,pb[u],w);
            }
        }
        dij(pa[s]);
        return 0;
    }
    
  • 相关阅读:
    Raneto Docs(开源的知识库建站程序)
    Elasticsearch索引(company)_Centos下CURL增删改
    Elasticsearch配置详解、文档元数据
    Easticsearch通信方式_API
    全文检索学习历程目录结构(Lucene、ElasticSearch)
    Linux(CentOS 6.7)下配置Mono和Jexus并且部署ASP.NET MVC3、4、5和WebApi(跨平台)
    Apache Lucene(全文检索引擎)—分词器
    Apache Lucene(全文检索引擎)—搜索
    Apache Lucene(全文检索引擎)—创建索引
    Nginx主配置参数详解,Nginx配置网站
  • 原文地址:https://www.cnblogs.com/Repulser/p/9785688.html
Copyright © 2020-2023  润新知