CF786B/CF787D

线段树优化建图板子题

首先暴力建图显然是不可取的,但是我们发现建图要求是点和区间之间的问题,所以考虑用线段树优化

但是怎么优化呢?

如果用一棵线段树很难处理同时出边和入边,因此我们考虑用两棵线段树(类似拆点),一棵线段树作为起点,另一棵线段树作为终点,然后在两棵线段树之间连边即可

这样的话连边的方式也就是起点线段树中一个节点(代表一个点或一段区间)向终点线段树中一个节点(代表一个点或一段区间),起点线段树从下向上连边,终点线段树从上向下连边,终点线段树叶节点向对应起点线段树叶节点连边即可

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define rt1 (rt<<1)
#define rt2 ((rt<<1)|1)
using namespace std;
struct Edge
{
    int nxt;
    int to;
    ll val;
}edge[5000005];
struct node
{
    int p;
    ll v;
    node (){}
    node (int x,ll y):p(x),v(y){}
    friend bool operator < (node a,node b)
    {
        return a.v>b.v;
    }
};
int pos1[100005];
int pos2[100005];
int head[800005];
bool vis[800005];
ll dis[800005];
int cnt=1;
int n,q,s;
void add(int l,int r,ll w)
{
    edge[cnt].nxt=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
void buildtree1(int rt,int l,int r)
{
    if(l==r){pos1[l]=rt;return;}
    int mid=(l+r)>>1;
    buildtree1(rt1,l,mid),buildtree1(rt2,mid+1,r);
    add(rt1,rt,0),add(rt2,rt,0);
}
void buildtree2(int rt,int l,int r)
{
    if(l==r){pos2[l]=rt+4*n;return;}
    int mid=(l+r)>>1;
    buildtree2(rt1,l,mid),buildtree2(rt2,mid+1,r);
    add(rt+4*n,rt1+4*n,0),add(rt+4*n,rt2+4*n,0);
}
template <typename T>inline void read(T &x)
{
    T f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x=f*c;
}
void query_add1(int rt,int l,int r,int lq,int rq,int v,ll w)//区间->点
{
    if(l>=lq&&r<=rq){add(rt,v,w);return;}
    int mid=(l+r)>>1;
    if(lq<=mid)query_add1(rt1,l,mid,lq,rq,v,w);
    if(rq>mid)query_add1(rt2,mid+1,r,lq,rq,v,w);
}
void query_add2(int rt,int l,int r,int lq,int rq,int v,ll w)//点->区间
{
    if(l>=lq&&r<=rq){add(v,rt+4*n,w);return;}
    int mid=(l+r)>>1;
    if(lq<=mid)query_add2(rt1,l,mid,lq,rq,v,w);
    if(rq>mid)query_add2(rt2,mid+1,r,lq,rq,v,w);
}
void diji()
{
    memset(dis,0x3f,sizeof(dis));
    dis[pos1[s]]=dis[pos2[s]]=0;
    priority_queue <node> Q;
    Q.push(node(pos1[s],0));
    while(!Q.empty())
    {
        node u=Q.top();
        Q.pop();
        if(vis[u.p])continue;
        vis[u.p]=1;
        for(int i=head[u.p];i;i=edge[i].nxt)
        {
            int to=edge[i].to;
            if(dis[to]>dis[u.p]+edge[i].val&&!vis[to])dis[to]=dis[u.p]+edge[i].val,Q.push(node(to,dis[to]));
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(dis[pos2[i]]==0x3f3f3f3f3f3f3f3fll)printf("-1 ");
        else printf("%lld ",dis[pos2[i]]);
    }
    printf("\n");
}
int main()
{
    read(n),read(q),read(s);
    buildtree1(1,1,n),buildtree2(1,1,n);
    for(int i=1;i<=n;i++)add(pos2[i],pos1[i],0);
    while(q--)
    {
        int typ;
        ll w;
        read(typ);
        if(typ==1)
        {
            int st,ed;
            read(st),read(ed),read(w);
            add(pos1[st],pos2[ed],w);
        }else if(typ==2)
        {
            int lq,rq,st;
            read(st),read(lq),read(rq),read(w);
            query_add2(1,1,n,lq,rq,pos1[st],w);
        }else
        {
            int lq,rq,ed;
            read(ed),read(lq),read(rq),read(w);
            query_add1(1,1,n,lq,rq,pos2[ed],w);
        }
    }
    diji();
    return 0;
}

 

posted @ 2019-07-04 11:01  lleozhang  Views(450)  Comments(0Edit  收藏  举报
levels of contents