3641-货车运输-函数式线段树-分类讨论-环套树

3641: 货车运输

Time Limit: 20 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 64  Solved: 27
[Submit][Status][Discuss]

Description

saffah所在的国家一共有N个城市,通过N条双向道路连接,使得城市之间两两可以到达。第i条道路连接了A[i]与B[i],其长度为L[i] km。
这些道路分为M个等级。第i条道路的等级为X[i]。在第j级道路上行驶,你的限速是V[j] km/h,并且每行驶1小时会收取W[j]元的费用。根据道路分级的意义,V[j]与W[j]都随着j单调变化,即对于1 ≤ j < M,满足V[j] > V[j+1], W[j] > W[j+1]。
现在有Q辆货车需要运送货物。第k辆货车要从S[k]前往T[k],并且其最大速度为U[k] km/h。你需要对每辆货车求出其最小运送花费。

Input

第一行三个整数N, M, Q。
接下来N行,每行四个整数A[i], B[i], L[i], X[i],描述了一条道路。
接下来M行,每行两个整数V[j], W[j],描述了一个道路等级的限速和费用。
接下来Q行,每行三个整数S[k], T[k], U[k],描述了一辆货车。

Output

输出Q行,即每辆货车的最小运送花费。
你可以输出任意多位的实数,只要与标准答案的相对或绝对误差不超过0.0001就算正确。

Sample Input

4 2 2
1 2 50 1
2 3 50 1
1 3 50 2
3 4 50 1
100 20
10 10
1 4 100
1 4 10

Sample Output

30
150

HINT

对于所有的数据,1 ≤ N,M,Q ≤ 100,000, 1 ≤ A[i],B[i],S[k],T[k] ≤ N, 1 ≤ X[i] ≤ M, 1 ≤ L[i],V[j],W[j],U[k] ≤ 500,000。

样例解释:

第一辆货车应该沿1→2→3→4行驶,共在1级道路上行驶1.5小时,收费30元。

第二辆货车应该沿1→3→4行驶,在2级道路上行驶5小时,在1级道路上行驶5小时,收费150元。

出题人真是调皮,上来就给8个数组。。

傻逼代码题。。调了蛮久(主要是数据。。找了半天。。CH各种坑啊。。)。。最后发现

    rep(i, 1, cCnt) {
        dep[cir[i]] = 1;
    }

写成:

    rep(i, 1, cCnt) {
        dep[i] = 1;
    }

23333

rk3的代码。。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <cmath>
  6 #include <string>
  7 #include <vector>
  8 #include <map>
  9 #include <set>
 10 #include <queue>
 11 #include <climits>
 12 #include <cstdlib>
 13 #include <ctime>
 14 using namespace std;
 15 namespace my_useful_tools {
 16 #define rep(_i, _k, _j) for(int _i = _k; _i <= _j; ++_i)
 17 #define reu(_i, _k, _j) for(int _i = _k; _i <  _j; ++_i)
 18 #define red(_i, _k, _j) for(int _i = _k; _j <= _i; --_i)
 19 #define foreach(_i, _s) for(typeof(_s.begin()) _i = _s.begin(); _i != _s.end(); ++_i)
 20 #define pb push_back
 21 #define mp make_pair
 22 #define ipir pair<int, int>
 23 #define ivec vector<int>
 24 #define clr(t) memset(t, 0, sizeof t)
 25 #define pse(t, v) memset(t, v, sizeof t)
 26 #define brl puts("")
 27 #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
 28 #define file_hza freopen("input.txt", "r", stdin), freopen("output.txt", "w", stdout);
 29 #define file_gen(x) freopen(#x".in", "w", stdout);
 30     const int INF = 0x3f3f3f3f;
 31     typedef long long LL;
 32     typedef long double DB;
 33     inline void pc(char c) { putchar(c); }
 34     template<class T> inline T gcd(T a, T b) { return b == 0 ? a : gcd(b, a % b); }
 35     inline char gchar() { char ret = getchar(); for(; ret == ‘\n‘ || ret == ‘\r‘ || ret == ‘ ‘; ret = getchar()); return ret; }
 36     template<class T> inline void fr(T&ret) { char c = ‘ ‘; int flag = 1; for(c = getchar(); c != ‘-‘ && !(‘0‘ <= c && c <= ‘9‘); c = getchar());
 37         if(c == ‘-‘) flag = -1, ret = 0; else ret = c - ‘0‘; for(c = getchar(); ‘0‘ <= c && c <= ‘9‘; c = getchar()) ret = ret * 10 + c - ‘0‘;
 38         ret = ret * flag;
 39     }
 40     inline int fr() { int x; fr(x); return x; }
 41     template<class T> inline void fr(T&a, T&b) { fr(a), fr(b); } template<class T> inline void fr(T&a, T&b, T&c) { fr(a), fr(b), fr(c); }
 42     template<class T> inline T fast_pow(T base, T index, T mod = 2147483647, T ret = 1) {
 43         for(; index; index >>= 1, base = base * base % mod) if(index & 1) ret = ret * base % mod;
 44         return ret;
 45     }
 46 };
 47 using namespace my_useful_tools;
 48
 49 const int maxn = 1e5 + 100;
 50
 51
 52 int e, h[maxn], to[maxn*2], nxt[maxn*2], dis[maxn*2], rnk[maxn*2];
 53 void addEdge(int u, int v, int c, int d) {
 54     nxt[e] = h[u], to[e] = v, rnk[e] = c, dis[e] = d, h[u] = e++;
 55     nxt[e] = h[v], to[e] = u, rnk[e] = c, dis[e] = d, h[v] = e++;
 56 }
 57
 58 int V[maxn], W[maxn];
 59 int n, m, q;
 60
 61 int fa[maxn], pa[maxn][21], cir[maxn], cCnt, onCir[maxn], dep[maxn], owner[maxn], lnk[maxn];
 62
 63 void get_cir(int u) {
 64     //printf("%d\n", u);
 65     for (int i=h[u]; i !=-1; i=nxt[i]) {
 66         if (i != fa[u]) {
 67             if (dep[to[i]] > 0) {
 68                 cir[++cCnt] = u;
 69                 lnk[cCnt] = fa[u];
 70                 while (u != to[i]) {
 71                     u = to[fa[u]];
 72                     cir[++cCnt] = u;
 73                     lnk[cCnt] = fa[u];
 74                 }
 75                 lnk[cCnt] = i;
 76                 break;
 77             }
 78             fa[to[i]] = i^1;
 79             dep[to[i]] = dep[u]+1;
 80             get_cir(to[i]);
 81             if (cCnt != 0) break;
 82         }
 83     }
 84 }
 85
 86 const int maxNode = ((maxn<<2)+maxn*30)*2;
 87 #define cn cmt_node
 88 #define lc ch[0]
 89 #define rc ch[1]
 90 struct cmt_node {
 91     cn*ch[2];
 92     long double a, b;
 93     cn() {
 94         ch[0] = ch[1] = NULL;
 95         a = b = 0.0;
 96     }
 97 } pool[maxNode], *loc=pool, *root, *trt[maxn], *crt[maxn];
 98
 99 void build(int l, int r, cn*&rt) {
100     if (rt == NULL)
101         rt = loc++;
102     if (l == r) return ;
103     int mid=(l+r)>>1;
104     build(l, mid, rt->lc);
105     build(mid+1, r, rt->rc);
106 }
107
108 int rk;
109 long double aa, ab;
110 void insert(int l, int r, cn*&rt, cn*pre) {
111     rt = loc++;
112     rt->a = pre->a+aa, rt->b = pre->b+ab;
113     if (l == r) return ;
114     int mid = (l+r)>>1;
115     if (rk <= mid) rt->rc=pre->rc, insert(l, mid, rt->lc, pre->lc);
116     else rt->lc=pre->lc, insert(mid+1, r, rt->rc, pre->rc);
117 }
118 long double queryA(int ql, int qr, int l, int r, cn*ra, cn*rb, cn*f) {
119     if (ql <= l && r <= qr) {
120         return ra->a + rb->a - 2.0*f->a;
121     }
122     int mid = (l+r)>>1;
123     long double ret = 0.0;
124     if (ql <= mid) ret += queryA(ql, qr, l, mid, ra->lc, rb->lc, f->lc);
125     if (mid < qr) ret += queryA(ql, qr, mid+1, r, ra->rc, rb->rc, f->rc);
126     return ret;
127 }
128 long double queryB(int ql, int qr, int l, int r, cn*ra, cn*rb, cn*f) {
129     if (ql <= l && r <= qr) {
130         return ra->b + rb->b - 2.0*f->b;
131     }
132     int mid = (l+r)>>1;
133     long double ret = 0.0;
134     if (ql <= mid) ret += queryB(ql, qr, l, mid, ra->lc, rb->lc, f->lc);
135     if (mid < qr) ret += queryB(ql, qr, mid+1, r, ra->rc, rb->rc, f->rc);
136     return ret;
137 }
138 long double queryA(int ql, int qr, int l, int r, cn*ra, cn*rb) {
139     if (ql <= l && r <= qr) {
140         return rb->a - ra->a;
141     }
142     int mid = (l+r)>>1;
143     long double ret = 0.0;
144     if (ql <= mid) ret += queryA(ql, qr, l, mid, ra->lc, rb->lc);
145     if (mid < qr) ret += queryA(ql, qr, mid+1, r, ra->rc, rb->rc);
146     return ret;
147 }
148 long double queryB(int ql, int qr, int l, int r, cn*ra, cn*rb) {
149     if (ql <= l && r <= qr) {
150         return rb->b - ra->b;
151     }
152     int mid = (l+r)>>1;
153     long double ret = 0.0;
154     if (ql <= mid) ret += queryB(ql, qr, l, mid, ra->lc, rb->lc);
155     if (mid < qr) ret += queryB(ql, qr, mid+1, r, ra->rc, rb->rc);
156     return ret;
157 }
158
159 void dfs(int u, int f, int top) {
160     /*
161     if (u == 93078) {
162         printf("93078 %d\n", top);
163     }
164     if (u == 14257) {
165         printf("14257 %d\n", top);
166     }
167     */
168     owner[u] = top;
169     //pa[u][0] = f;
170     for (int i=h[u]; i!=-1; i=nxt[i])
171         if (to[i] != f && !onCir[to[i]]) {
172             pa[to[i]][0] = u;
173             dep[to[i]] = dep[u]+1;
174             rk = rnk[i];
175             aa = (DB)dis[i]*W[rk];
176             ab = (DB)dis[i]/V[rk]*W[rk];
177             insert(1, m, trt[to[i]], trt[u]);
178             dfs(to[i], u, top);
179         }
180 }
181
182 int lca(int u, int v) {
183     if (dep[u] < dep[v]) swap(u, v);
184     red(i, 20, 0)
185         if (dep[pa[u][i]] >= dep[v])
186             u = pa[u][i];
187     if (u == v) return u;
188     red(i, 20, 0)
189         if (pa[u][i] != pa[v][i])
190             u=pa[u][i], v=pa[v][i];
191     return pa[u][0];
192 }
193
194 vector<int> rV;
195 vector<int>::iterator it;
196 int getRank(int u) {
197     it = upper_bound(rV.begin(), rV.end(), u);
198     if (it == rV.end()) return 1;
199     int v = it-rV.begin();
200     return m-v+1;
201 }
202 long double qMinCost(int s, int t, int u, int r) {
203     if (s == t) return 0;
204     int f = lca(s, t);
205     long double ret = 0.0;
206     if (1 <= r-1) ret += queryA(1, r-1, 1, m, trt[s], trt[t], trt[f])/u;
207     if (r <= m) ret += queryB(r, m, 1, m, trt[s], trt[t], trt[f]);
208     return ret;
209 }
210 long double qMinCost2(int s, int t, int u, int r) {
211     if (t <= s) return 0;
212     long double ret = 0.0;
213     if (1 <= r-1) ret += queryA(1, r-1, 1, m, crt[s], crt[t])/(long double)u;
214     if (r <= m) ret += queryB(r, m, 1, m, crt[s], crt[t]);
215     return ret;
216 }
217
218 int main() {
219     fr(n, m, q);
220     root = NULL;
221     build(1, m, root);
222     trt[0] = crt[0] = root;
223     rep(i, 1, n) trt[i] = NULL;
224     e = 0, pse(h, -1);
225     int a, b, c, d;
226     rep(i, 1, n) {
227         fr(a, b), fr(d, c);
228         addEdge(a, b, c, d);
229     }
230     rep(i, 1, m)
231         fr(V[i], W[i]);
232     pse(fa, -1);
233     dep[1] = 1;
234     get_cir(1);
235     rep(i, 1, cCnt)
236         onCir[cir[i]] = i;
237     dep[0] = 0;
238     crt[0] = root;
239     rep(i, 1, cCnt) {
240         dep[cir[i]] = 1;
241         trt[cir[i]] = root;
242         dfs(cir[i], 0, cir[i]);
243         crt[i] = NULL;
244         int p = (i==1?lnk[cCnt]:lnk[i-1]);
245         rk = rnk[p];
246         aa = (DB)dis[p]*W[rk];
247         ab = (DB)dis[p]*W[rk]/V[rk];
248         insert(1, m, crt[i], crt[i-1]);
249     }
250     rep(j, 1, 20)
251         rep(i, 1, n)
252         pa[i][j] = pa[pa[i][j-1]][j-1];
253
254     rep(i, 1, m)
255         rV.pb(V[i]);
256     reverse(rV.begin(), rV.end());
257     int s, t, u, r;
258     while (q--) {
259         fr(s, t, u);
260         long double ans = 0.0;
261         r = getRank(u);
262         if (owner[s] == owner[t]) {
263             ans = qMinCost(s, t, u, r);
264         } else {
265             if (onCir[owner[t]] < onCir[owner[s]])
266                 swap(s, t);
267             ans += qMinCost(s, owner[s], u, r);
268             ans += qMinCost(t, owner[t], u, r);
269             long double x = qMinCost2(onCir[owner[s]], onCir[owner[t]], u, r);
270             long double y = qMinCost2(1, onCir[owner[s]], u, r);
271             long double z = qMinCost2(onCir[owner[t]], cCnt, u, r);
272             long double w = qMinCost2(0, 1, u, r);
273             ans += min(x, y+z+w);
274         }
275         printf("%lf\n", (double)ans);
276     }
277
278     return 0;
279 }

时间: 2024-08-26 05:55:27

3641-货车运输-函数式线段树-分类讨论-环套树的相关文章

BZOJ 1099([POI2007]树Drz-9次线段树&amp;分类讨论+线段树与插入顺序维护2个参数)

1099: [POI2007]树Drz Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 142  Solved: 55 [Submit][Status] Description CDQZ是一个偏远的小学校,FGD在学校里中了一排树.他却不喜欢这些树的顺序,因为他们高高矮矮显得那么参差不齐. FGD定义这些树的不整齐程度为相邻两树的高度差的和.设树高分别为h1,h2,h3,-,hn.那么不整齐程度定义为:|h1-h2|+|h2-h3|+--+|hn

TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (环套树 + 分类讨论)

题意  给定一个$n$个点$n$条边的无向图,现在要把这个图进行若干次操作,并选择一个点作为首都. 要求除首都外的任意两个点$u$, $v$,从$u$走到$v$必须经过这个首都. 操作为合并两个相邻的点为一个点,即把这两个点从原图中删除,连接这两个点的边接到新的点上去. 考虑最后这个图的形态其实是一个菊花图,那么可以考虑到最后剩下的这些点其实只有选出的首都和 原图中度数为$1$的点. 但是有这么一种比较特殊的情况. 这个图也是符合题意的. 原来的图其实是一个环套树(环的大小可能为$2$) 如果这

【线段树】【分类讨论】水果姐逛水果街Ⅰ

3304 水果姐逛水果街Ⅰ 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 水果姐今天心情不错,来到了水果街. 水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. 学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价. 就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店

HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5957 题意:D(u,v)是节点u和节点v之间的距离,S(u,v)是一系列满足D(u,x)<=k的点的集合,操作1:将S(u,k)内节点权值增加或者减小,操作2:查询S(u,k)内节点的权值和 题解:因为题目说了查询和更新的距离小于等于k,k最大为2,所以很显然要分情况讨论k为0.1.2的情况 因为是多次更新,我们显然是需要用线段树来维护节点权值的 运用线段树和bfs序的知识我们知道 对一个棵树求BFS

【树链剖分】【dfs序】【LCA】【分类讨论】Codeforces Round #425 (Div. 2) D. Misha, Grisha and Underground

一棵树,q次询问,每次给你三个点a b c,让你把它们选做s f t,问你把s到f +1后,询问f到t的和,然后可能的最大值是多少. 最无脑的想法是链剖线段树--但是会TLE. LCT一样无脑,但是少一个log,可以过. 正解是分类讨论, 如果t不在lca(s,f)的子树内,答案是dis(lca(s,f),f). 如果t在lca(s,f)的子树内,并且dep(lca(s,t))>dep(lca(f,t)),答案是dis(lca(s,t),f): 否则答案是dis(lca(f,t),f). #in

POJ 2826 An Easy Problem?!(线段相交,分类讨论)

题意:给两个线段,问他们能收集到多少雨水. 链接:http://poj.org/problem?id=2826 解法:分四种情况讨论 1. 存在一个线段与x轴平行,答案为0 2. 两个线段没有交点,答案为0 3. 1和2都不满足时,令线段1为比较低的那个线段,且p1为其比较高的那个点,若该点往y轴正方向的射线与线段2有交点,则答案为0 4. 3不满足时,求出两线段交点x1,p1做一条平行于x轴的线,该线与线段2的交点x2,则三角形x1, x2, p1的面积就是答案 小结:此题属于分类讨论型的题,

Codeforces538F A Heap of Heaps(函数式线段树)

题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力,因为完全k叉树当k很大的时候,其实层数是特别小的,所以感觉暴力是可以的.注意到一个完全k叉树下v节点的儿子的公式是: k*(v-1)+2...kv+1,相应的父节点的公式是 (v+k-2)/k.儿子的编号是连续的,如果我们可以对每个节点快速的求出连续编号的节点有多少个数比它小我们就可以快速的更新答案

主席树(函数式线段树)学习小结(附手绘讲解图片)

主席树是一种离线数据结构,是由很多棵线段树组成的. 第i棵线段树存的是前i个数的信息: 每一个线段存数字的出现次数(因此建树之前要离散化). 那么n棵线段树不会MLE吗? 当然会了! 但是我们发现第i棵线段树和第i-1棵线段树是非常相似的,有许多结点完全相同,因此可以借用之前的结点,没必要新建结点. 具体建树方法建下图: 序列为 1 3 4 2 那么如果要询问i-j之间数字出现的次数怎么办呢? 因为每一棵线段树的区间都是相同的,所以要求l-r之间的数字的出现次数只要用前r位出现的次数减去前l-1

HDU-4866-Shooting(函数式线段树)

Problem Description In the shooting game, the player can choose to stand in the position of [1, X] to shoot, you can shoot all the nearest K targets. The value of K may be different on different shootings. There are N targets to shoot, each target oc