CF786B Legacy(线段树优化建图)
Posted captain1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(‘ ‘) 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 ",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; }
以上是关于CF786B Legacy(线段树优化建图)的主要内容,如果未能解决你的问题,请参考以下文章