CF-787D-线段树建图+最短路
http://codeforces.com/problemset/problem/787/D
题目大意是给出一个有向图,有N个节点,初始节点在S,询问S到所有点最短路。边的读入方式有三种, 1 u v w 表示 u->v有一条边权为w的边, 2 v l r w ,表示v->[l,r]内的任意一个点支付w即可,
3 v l r w 表示从[l,r]内任意一个点到v支付w即可。直接构图的话可能会出现完全图,被卡死。
一种巧妙的构图方式是,由这些个区间联想到线段树(然而我并没有想到),我们不妨对2,3两种类型建立两颗线段树 他们的叶子节点是共用的(1--N),对于2来说,如果节点v到树上的某个节点x有一条w的边,
就表示v到这个节点所对应的区间的点都可以支付w到达,并且在2的内部所有的父亲都向自己的儿子建立一条边权为0的边,这样如果v能到达x,说明v能到达x所有的子孙节点(支付w),对于3来说只不过反过来了一下思路一样。
建完图之后跑最短路就好了,节点数大约N*10够了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define ULL unsigned long long 5 #define pii pair<int,int> 6 #define mid ((L+R)>>1) 7 #define lc (id<<1) 8 #define rc (id<<1|1) 9 #define pb push_back 10 #define mp make_pair 11 #define inf 0x3f3f3f3f 12 #define linf 0xffffffffffff 13 const int maxn=100010; 14 int N,Q,S,T0,T1,CNT; 15 int ch[maxn*10][2]; 16 LL d[maxn*10]; 17 bool in[maxn*10]; 18 int tot,first[maxn*10]; 19 struct Edge{int v,w,next;}e[maxn*20]; 20 void add(int u,int v,int w){ 21 e[tot].v=v; 22 e[tot].w=w; 23 e[tot].next=first[u]; 24 first[u]=tot++; 25 } 26 void build1(int &p,int L,int R){ 27 if(L==R) p=L; 28 else{ 29 p=++CNT; 30 build1(ch[p][0],L,mid),build1(ch[p][1],mid+1,R); 31 add(p,ch[p][0],0),add(p,ch[p][1],0); 32 } 33 } 34 35 void build2(int &p,int L,int R){ 36 if(L==R) p=L; 37 else{ 38 p=++CNT; 39 build2(ch[p][0],L,mid),build2(ch[p][1],mid+1,R); 40 add(ch[p][0],p,0),add(ch[p][1],p,0); 41 } 42 } 43 void insert1(int id,int L,int R,int v,int l,int r,int w){ 44 if(L>=l&&R<=r){ 45 add(v,id,w); 46 return; 47 } 48 if(l<=mid)insert1(ch[id][0],L,mid,v,l,r,w); 49 if(r>mid)insert1(ch[id][1],mid+1,R,v,l,r,w); 50 } 51 52 void insert2(int id,int L,int R,int v,int l,int r,int w){ 53 if(L>=l&&R<=r){ 54 add(id,v,w); 55 return; 56 } 57 if(l<=mid)insert2(ch[id][0],L,mid,v,l,r,w); 58 if(r>mid)insert2(ch[id][1],mid+1,R,v,l,r,w); 59 } 60 void spfa(){ 61 for(int i=0;i<=CNT;++i)d[i]=linf; 62 memset(in,0,sizeof(in)); 63 queue<int>q; 64 q.push(S); 65 in[S]=1; 66 d[S]=0; 67 while(!q.empty()){ 68 int u=q.front(); 69 q.pop(); 70 for(int i=first[u];~i;i=e[i].next){ 71 if(d[e[i].v]>d[u]+e[i].w){ 72 d[e[i].v]=d[u]+e[i].w; 73 if(!in[e[i].v]){ 74 q.push(e[i].v); 75 } 76 } 77 } 78 } 79 for(int i=1;i<=N;++i) printf("%lld%c",d[i]==linf?-1:d[i],i==N?'\n':' '); 80 } 81 int main() 82 { 83 memset(first,-1,sizeof(first)); 84 tot=0; 85 scanf("%d%d%d",&N,&Q,&S); 86 CNT=N; 87 build1(T0,1,N); 88 build2(T1,1,N); 89 int opt,u,v,w,l,r; 90 while(Q--){ 91 scanf("%d",&opt); 92 if(opt==1){ 93 scanf("%d%d%d",&u,&v,&w); 94 add(u,v,w); 95 } 96 else{ 97 scanf("%d%d%d%d",&v,&l,&r,&w); 98 if(opt==2){ 99 insert1(T0,1,N,v,l,r,w); 100 } 101 else{ 102 insert2(T1,1,N,v,l,r,w); 103 } 104 } 105 } 106 spfa(); 107 return 0; 108 } 109 /*0 -1-112 110 0 -1 -1 12 111 */