zoj 3724 Delivery 离线处理+线段树
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define ll long long 6 using namespace std; 7 int n,m,t,tol,tt; 8 ll f[100010]; 9 ll sum[100010]; 10 struct edge{ 11 int u,v,x; 12 ll l; 13 edge(){} 14 edge(int u,int v,ll l,int x):u(u),v(v),l(l),x(x){} 15 friend bool operator<(edge a,edge b){ 16 if(a.u!=b.u) return a.u>b.u; 17 else if(a.v!=b.v) return a.v<b.v; 18 else return a.x<b.x; 19 } 20 }e[800010],te[800010]; 21 struct tree{ 22 int l,r; 23 ll maxc,lz; 24 }a[800010]; 25 ll ans[200010]; 26 void build(int l,int r,int k){ 27 a[k].l=l,a[k].r=r; 28 a[k].maxc=a[k].lz=0; 29 if(l<r){ 30 int mid=(l+r)>>1; 31 build(l,mid,k<<1); 32 build(mid+1,r,k<<1|1); 33 } 34 } 35 void pushdown(int k){ 36 if(a[k].lz!=0){ 37 a[k<<1].maxc=max(a[k].lz,a[k<<1].maxc); 38 a[k<<1|1].maxc=max(a[k].lz,a[k<<1|1].maxc); 39 a[k<<1].lz=max(a[k<<1].lz,a[k].lz); 40 a[k<<1|1].lz=max(a[k<<1|1].lz,a[k].lz); 41 a[k].lz=0; 42 } 43 } 44 void insert(int l,int r,ll c,int k){ 45 if(l<=a[k].l&&a[k].r<=r){ 46 a[k].maxc=max(a[k].maxc,c); 47 a[k].lz=max(a[k].lz,c); 48 }else{ 49 pushdown(k); 50 int mid=(a[k].l+a[k].r)>>1; 51 if(r<=mid) insert(l,r,c,k<<1); 52 else if(l>mid) insert(l,r,c,k<<1|1); 53 else insert(l,mid,c,k<<1),insert(mid+1,r,c,k<<1|1); 54 a[k].maxc=max(a[k<<1].maxc,a[k<<1|1].maxc); 55 } 56 } 57 ll query(int l,int r,int k){ 58 if(l<=a[k].l&&a[k].r<=r){ 59 return a[k].maxc; 60 }else{ 61 pushdown(k); 62 int mid=(a[k].l+a[k].r)>>1; 63 if(r<=mid) return query(l,r,k<<1); 64 else if(l>mid) return query(l,r,k<<1|1); 65 else return max(query(l,mid,k<<1),query(mid+1,r,k<<1|1)); 66 } 67 } 68 void read(){ 69 for(int i=1;i<n;i++) scanf("%lld",&f[i]); 70 int u,v; 71 ll l; 72 tol=tt=0; 73 f[n]=(ll)1e12; 74 for(int i=0;i<m;i++){ 75 scanf("%d%d%lld",&u,&v,&l); 76 if(u==v) continue; 77 if(u==n&&v==1) f[n]=min(f[n],l); 78 if(u<v) e[tol++]=edge(u,v,l,0); 79 else te[tt++]=edge(u,v+n,l,0); 80 } 81 scanf("%d",&t); 82 for(int i=0;i<t;i++){ 83 scanf("%d%d",&u,&v); 84 if(u<=v) e[tol++]=edge(u,v,(ll)i,1); 85 else te[tt++]=edge(u,v+n,(ll)i,1); 86 } 87 } 88 void gao(){ 89 sum[0]=0; 90 for(int i=1;i<n;i++) sum[i]=sum[i-1]+f[i]; 91 sort(e,e+tol); 92 build(1,n,1); 93 for(int i=0;i<tol;i++){ 94 if(e[i].x==0){ 95 insert(e[i].v,n,sum[e[i].v-1]-sum[e[i].u-1]-e[i].l,1); 96 }else{ 97 ans[e[i].l]=sum[e[i].v-1]-sum[e[i].u-1]-query(e[i].u,e[i].v,1); 98 } 99 } 100 sort(te,te+tt); 101 build(1,2*n-1,1); 102 for(int i=0;i<tt;i++){ 103 int u=te[i].u,v=te[i].v-n; 104 if(te[i].x==0){ 105 insert(v+n,2*n-1,f[n]+sum[n-1]-sum[u-1]+sum[v-1]-te[i].l,1); 106 }else{ 107 ans[te[i].l]=f[n]+sum[n-1]-sum[u-1]+sum[v-1]-query(u,v+n,1); 108 } 109 } 110 } 111 void out(){ 112 for(int i=0;i<t;i++){ 113 printf("%lld\n",ans[i]); 114 } 115 } 116 int main(){ 117 while(~scanf("%d%d",&n,&m)){ 118 read(); 119 gao(); 120 out(); 121 } 122 return 0; 123 }
解题思路:
由于题目中说短边只会走一次,所以可以发现,往前和往后是不影响的,可以分开讨论。
然后线段树中记录的走短边的话最多可以省多少,
离线处理,将修改和询问放一起,先按u从大到小,再按v从小到大排序,以上都一样时,修改优先。
当u<=v时,插入的线段是[v,n],大小置为u到v的原长度-短边,询问雷同。
当u>v时,我的做法是将线段树延伸到2*n-1处,那么线段就变为[u,v+n],那么排序和插入的做法和上面一样。