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;
}
 
posted @ 2018-10-26 20:34  PushinL  阅读(311)  评论(0编辑  收藏  举报