• [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;
    }
    
  • 相关阅读:
    【纯水题】POJ 1852 Ants
    【树形DP】BZOJ 1131 Sta
    【不知道怎么分类】HDU
    【树形DP】CF 1293E Xenon's Attack on the Gangs
    【贪心算法】CF Emergency Evacuation
    【思维】UVA 11300 Spreading the Wealth
    【树形DP】NOI2003 逃学的小孩
    【树形DP】BZOJ 3829 Farmcraft
    【树形DP】JSOI BZOJ4472 salesman
    【迷宫问题】CodeForces 1292A A NEKO's Maze Game
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13549628.html
Copyright © 2020-2023  润新知