• CF787D Legacy


    区间连边的图题

    线段树优化建图

    然而我懒得写线段树

    写暴力!暴力!

    于是用了书名号魔改线段树优化建图的方法:点和区间连边时,新建一个点,把两个点连上权值为val的边,然后把区间向新点连权值为0的边(还是个暴力

    前面的点跑的比暴力快然而从第8个点开始RE 再大就MLE了qwq

    老老实实写线段树吧孩子!

    暴力CODE:

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define ll long long
    #define pii pair<ll, int>
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    int n, q, s;
    struct edge{
        int go, nxt, val;
    }e[6000005];
    int head[6000005], vis[6000005];
    ll dis[6000005];
    priority_queue<pii, vector<pii> ,greater<pii> >qu;
    inline int qr(){
        int x=0;
        char ch=getchar();
        for(; isdigit(ch); ch=getchar()) x=x*10+ch-48;
        return x;
    }
    void add(int u, int v, int w){
        static int tot;
        e[++tot].nxt=head[u];
        e[tot].go=v;
        e[tot].val=w;
        head[u]=tot;
    }
    void dij(int s){
        for(int i=1; i<=n; i++)
            dis[i]=INF;
        dis[s]=0;
        qu.push(make_pair(0, s));
        while(!qu.empty()){
            int u=qu.top().second;
            qu.pop();
            if(vis[u])continue;
            vis[u]=1;
            for(int i=head[u]; i; i=e[i].nxt){
                int v=e[i].go;
                if(!vis[v]&&dis[u]+e[i].val<dis[v]){
                    dis[v]=dis[u]+e[i].val;
                    qu.push(make_pair(dis[v], v));
                }
            }
        }
    }
    int main(){
        n=qr();q=qr();s=qr();
        int qwq, a, b, c, d;
        for(int i=1; i<=q; i++){
            qwq=qr();
            if(qwq==1){
                a=qr();b=qr();c=qr();
                add(a, b, c);
            }else if(qwq==2){
                a=qr();b=qr();c=qr();d=qr();
                for(int i=b; i<=c; i++)
                    add(a, i, d);
            }else{
                a=qr();b=qr();c=qr();d=qr();
                for(int i=b; i<=c; i++)
                    add(i, a, d);
            }
        }
        dij(s);
        for(int i=1; i<=n; i++)
            printf("%lld ", dis[i]==INF?dis[i]=-1:dis[i]);
        return 0;
    }
    

    正解(两颗线段树CODE:

    #include<bits/stdc++.h>
    #define lson (i<<1)
    #define rson (i<<1|1)
     
    using namespace std;
    typedef long long ll;
    typedef pair< ll, int > pli;
    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];
    ll dis[N*8];
    int tot;
     
     
    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遍表示两个点在逻辑上是一个点
            //cout<<"**** u "<<tb[i].num<<" "<<pa[l]<<endl;
            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线段树的 区间建一条边
            //cout<<"****u "<<num<<" "<<tb[i].num<<endl;
            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);
        }
    }
     
    int n,m,q,s;
     
    void dij(int st)
    {
        memset(vis,0,sizeof(vis));
        for(int i=0;i<=8*n;i++) dis[i]=inf;
        dis[st]=0;
        pli tmp;
     
        priority_queue< pli,vector<pli> ,greater<pli> >q;
        q.push(pli(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;
                    //cout<<"*** v "<<v<<" "<<dis[v]<<" "<<ve[u][i].w<<endl;
                    q.push(pli(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()
    {
        int op,l,r,u,v;
        ll w;
        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",&op);
            if(op==1){
                scanf("%d %d %lld",&u,&v,&w);
                ve[pa[u]].push_back(node1(w,pb[v]));
            }
            else if(op==2){ // 从 u 到 l,r
                scanf("%d %d %d %lld",&u,&l,&r,&w);
                updateb(rtb,l,r,pa[u],w);
            }
            else if(op==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;
    }
     
    
  • 相关阅读:
    每个人都有属于自己的机会
    [转]Android动画开发——Animation动画效果
    [转]android 使用WebView
    深圳 2012 职称英语 报名
    [转]java中的io笔记
    [转]手机蓝牙各类服务对应的UUID(常用的几个已通过验证)
    [文摘20111215]急事慢慢说
    [转]Android XML解析
    [转]J2SE复习笔记2线程
    queryScopedSelector
  • 原文地址:https://www.cnblogs.com/pushinl/p/9858594.html
Copyright © 2020-2023  润新知