线段树优化建图板子题
首先暴力建图显然是不可取的,但是我们发现建图要求是点和区间之间的问题,所以考虑用线段树优化
但是怎么优化呢?
如果用一棵线段树很难处理同时出边和入边,因此我们考虑用两棵线段树(类似拆点),一棵线段树作为起点,另一棵线段树作为终点,然后在两棵线段树之间连边即可
这样的话连边的方式也就是起点线段树中一个节点(代表一个点或一段区间)向终点线段树中一个节点(代表一个点或一段区间),起点线段树从下向上连边,终点线段树从上向下连边,终点线段树叶节点向对应起点线段树叶节点连边即可
贴代码:
#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(" "); } 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; }