CF786B Legacy(线段树优化建图)

传送门

ovo这题该怎么做呢?我们首先考虑暴力建图,但是因为建图的操作太多直接就会MLE,所以这个就别想了……

我们考虑如何优化建图。因为发现一个点可以向一个区间连边,一个区间也可以向一个点连边,想到区间很容易想到线段树……所以我们可以使用一个点来代替一段区间进行建图。

具体的操作可以这样,我们建立两棵线段树,一棵用于存所有的出边(就是区间向点连边),每个点向其父亲建一条边权为0的边,另一棵用于存所有的入边(就是点向区间连边),每个点向其儿子建一条边权为0的边。然后对于线段树的每个叶子节点,与其编号对应的点连边。对于普通的点就直接在两点之间连边,否则的话,在不同的线段树上像区间修改一样连边即可。

最后直接从源点开始跑一边dij就可以了。话说这种题真是神奇……以前从未见过orz

记住这个题建图别建反了……还有就是极大值要开到longlong。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<set>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
#define pr pair<ll,int>
#define mp make_pair
#define fi first
#define sc second
const int M = 1000005;
const int N = 10000005;
 
int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >='0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct edge
{
    int next,to,v,from;
}e[M<<3];

int n,Q,s,cur,ecnt,head[M],lc[M],rc[M],root1,root2;
ll dis[M],INF;

set <pr> q;
set <pr> :: iterator it;
void add(int x,int y,int z)
{
    e[++ecnt].to = y;
    e[ecnt].v = z;
    e[ecnt].next = head[x];
    head[x] = ecnt;
}

void build1(int &p,int l,int r)//为了避免一些不必要的麻烦……我们选择记录左右儿子动态开点(直接左右移可能会有点小问题……也可能没有)
{
    if(l == r)
    {
    p = l;
    return;
    }
    p = ++cur;
    int mid = (l+r) >> 1;
    build1(lc[p],l,mid);
    build1(rc[p],mid+1,r);
    add(p,lc[p],0);
    add(p,rc[p],0);
}

void build2(int &p,int l,int r)
{
    if(l == r)
    {
    p = l;
    return;
    }
    p = ++cur;
    int mid = (l+r) >> 1;
    build2(lc[p],l,mid);
    build2(rc[p],mid+1,r);
    add(lc[p],p,0);
    add(rc[p],p,0);
}

void modify(int p,int l,int r,int u,int kl,int kr,int val,int flag)//像区间修改一样进行连边
{
    if(l == kl && r == kr)
    {
    if(flag == 2) add(u,p,val);
    else add(p,u,val);
    return;
    }
    int mid = (l+r) >> 1;
    if(kr <= mid) modify(lc[p],l,mid,u,kl,kr,val,flag);
    else if(kl > mid) modify(rc[p],mid+1,r,u,kl,kr,val,flag);
    else modify(lc[p],l,mid,u,kl,mid,val,flag),modify(rc[p],mid+1,r,u,mid+1,kr,val,flag);
    }
 /*void modify(int p,int l,int r,int u,int kl,int kr,int val,int flag)
{
    if(kl <= l && r <= kr)
    {
    flag == 2 ? add(u,p,val) : add(p,u,val);
    return;
    }
    int mid = (l+r) >> 1;
    if(kl <= mid) modify(lc[p],l,mid,u,kl,kr,val,flag);
    if(mid < kr) modify(rc[p],mid+1,r,u,kl,kr,val,flag);
    }*/

void dij(int s)
{
    memset(dis,0x3f,sizeof(dis));
    INF = dis[s];
    dis[s] = 0,q.insert(mp(dis[s],s));
    while(!q.empty())
    {
    pr k = *(q.begin());
    q.erase(q.begin());
    for(int i = head[k.sc];i;i = e[i].next)
    {
        if(dis[e[i].to] > dis[k.sc] + e[i].v)
        {
        it = q.find(mp(dis[e[i].to],e[i].to));
        if(it != q.end()) q.erase(it);
        dis[e[i].to] = dis[k.sc] + e[i].v;
        q.insert(mp(dis[e[i].to],e[i].to));
        }
    }
    }
}
int main()
{
    n = read(),Q = read(),s = read();
    cur = n;
    build1(root1,1,n);
    build2(root2,1,n);
    rep(i,1,Q)
    {
    int op = read();
    if(op == 1)
    {
        int x = read(),y = read(),z = read();
        add(x,y,z);
    }
    if(op == 2)
    {
        int x = read(),l = read(),r = read(),z = read();
        modify(root1,1,n,x,l,r,z,op);
    }
    if(op == 3)
    {
        int x = read(),l = read(),r = read(),z = read();
        modify(root2,1,n,x,l,r,z,op);
    }
    }
    //rep(i,1,ecnt) printf("%d %d %d\n",e[i].from,e[i].to,e[i].v);
    dij(s);
    rep(i,1,n) dis[i] < INF ? printf("%I64d ",dis[i]) : printf("-1 ");
    return 0;
}

 

posted @ 2018-09-18 20:19  CaptainLi  阅读(229)  评论(0编辑  收藏  举报