zoukankan      html  css  js  c++  java
  • [CF786B] Legacy

    前言

    第一道用线段树优化建边做的题,还是比较有记录意义的

    当然也有对Rick姥爷的膜拜 orz

    话说Rick为啥会给Morty留遗产

    题目

    洛谷

    CF

    讲解

    首先操作一有手就行

    问题是点连区间和区间连点的操作不好搞

    区间?你会想到什么?

    线段树!

    直接让线段树上的点连边,表示点连区间和区间连点

    但是我们发现一个问题,大区间可以由小区间组成,这会引起什么?

    大区间可以走向单点,组成它的小区间也可以走向单点

    单点可以走向小区间,单点也可以走向大区间

    细品这两句话↑

    所以我们需要两棵线段树分别维护走出去(从线段树走出去到单点,后者同理)和走进来

    一切都变得简单了,注意long long和数组大小

    我才不会用vector去卡空间,哼

    代码

    int head[MAXN * 9],tot;
    struct edge
    {
    	int v,w,nxt;
    }e[MAXN * 40];
    void Add_Edge(int x,int y,int z)
    {
    	e[++tot].v = y;
    	e[tot].w = z;
    	e[tot].nxt = head[x];
    	head[x] = tot;
    }
    
    int lc[MAXN * 9],rc[MAXN * 9],cnt;
    int Build(int l,int r,int t)
    {
    	if(l == r) return l;
    	int mid = (l+r) >> 1;
    	int x = ++cnt;
    	lc[x] = Build(l,mid,t);
    	rc[x] = Build(mid+1,r,t);
    	if(t == 1) Add_Edge(x,lc[x],0),Add_Edge(x,rc[x],0);//点连区间,往下走 
    	else Add_Edge(lc[x],x,0),Add_Edge(rc[x],x,0);//区间连点,往上走 
    	return x;
    }
    void update(int x,int l,int r,int ql,int qr,int ID,int val,int t)
    {
    	if(ql <= l && r <= qr)
    	{
    		if(t == 1) Add_Edge(ID,x,val);
    		else Add_Edge(x,ID,val);
    		return;
    	}
    	int mid = (l+r) >> 1;
    	if(ql <= mid) update(lc[x],l,mid,ql,qr,ID,val,t);
    	if(mid+1 <= qr) update(rc[x],mid+1,r,ql,qr,ID,val,t);
    }
    
    LL dis[MAXN * 9];
    struct node
    {
    	int u;LL val;
    	node(){}
    	node(int u1,LL val1){
    		u = u1;
    		val = val1;
    	}
    	bool operator < (const node &px)const{
    		return val > px.val;
    	}
    };
    void dijkstra()
    {
    	for(int i = 1;i <= cnt;++ i) dis[i] = INF;
    	priority_queue<node> q;
    	q.push(node(S,dis[S] = 0));
    	while(!q.empty())
    	{
    		node t = q.top(); q.pop();
    		if(t.val > dis[t.u]) continue;
    		for(int i = head[t.u]; i ;i = e[i].nxt)
    			if(dis[e[i].v] > dis[t.u] + e[i].w)
    				q.push(node(e[i].v,dis[e[i].v] = dis[t.u] + e[i].w));
    	}
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read(); S = Read();
    	cnt = n;
    	rt1 = Build(1,n,1); rt2 = Build(1,n,2);
    	while(m--)
    	{
    		int opt = Read(),u = Read(),l = Read(),r = Read();
    		if(opt == 1) Add_Edge(u,l,r);
    		else if(opt == 2) update(rt1,1,n,l,r,u,Read(),1);
    		else update(rt2,1,n,l,r,u,Read(),2);
    	}
    	dijkstra();
    	for(int i = 1;i <= n;++ i) Put(dis[i] == INF ? -1 : dis[i],' ');
    	return 0;
    }
    
  • 相关阅读:
    JAVA代码覆盖率工具JaCoCo-原理篇
    (转载)比较web ui 框架
    sql拼接
    解决com.mysql.jdbc.PacketTooBigException: Packet for query is too large问题
    字符串中重复出现字符串个数
    Unable to load annotation processor factory
    三目运算符
    WSGI剖析
    深入剖析cpp对象模型
    Cpp下匿名对象探究
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13549628.html
Copyright © 2011-2022 走看看