路径
【题目描述】
给定一个n个点每个点度数不超过2的无向图,支持两种操作
1.加入一条边[l,r],保证加入后图依然满足每个点度不超过2
2.求长度在[l,r]之间的不经过重复点的路径有多少条
注意:这里的路径长度定义为经过的点数而不是边数
【输入】
第一行三个正整数n,m,q表示点数,初始边数和操作数
接下来m行每行两个整数u,v表示u到v有一条边
接下来q行,每行三个整数op l r
【输出】
对于每个op=2输出答案
【样例】
path1.in |
path1.out |
8 5 8 1 2 2 3 4 5 5 6 7 8 2 2 3 1 4 6 2 3 3 2 1 2 1 1 7 2 3 5 1 3 8 2 1 8 |
7 4 14 9 34 |
path2.in |
path2.out |
4 0 5 1 1 2 1 2 3 1 3 4 1 4 1 2 1 4 |
16 |
大样例见下发文件path3.in/out,path4.in/out
【数据范围及约定】
对于100%的数据 1≤n,m,q≤500000 1≤l≤r≤n
性质1:没有修改操作
性质2:任意时刻一个联通块内任意两点之间路径唯一
性质3:任意时刻一个联通块内的点编号连续
下表给出了各测试点的数据规模和约定
编号 |
n,m |
q |
性质1 |
性质2 |
性质3 |
1 |
300 |
300 |
有 |
无 |
无 |
2 |
无 |
有 |
|||
3 |
无 |
||||
4 |
5000 |
2000 |
|||
5 |
|||||
6 |
5000 |
有 |
|||
7 |
无 |
有 |
|||
8 |
无 |
||||
9 |
100000 |
100000 |
有 |
有 |
|
10 |
无 |
有 |
|||
11 |
无 |
||||
12 |
无 |
||||
13 |
200000 |
有 |
|||
14 |
无 |
有 |
|||
15 |
200000 |
有 |
无 |
||
16 |
无 |
有 |
有 |
||
17 |
无 |
||||
18 |
|||||
19 |
无 |
||||
20 |
500000 |
500000
|
意思就是说只有简单环和链。
两条链合并,就是加两个等差数列和区间加法。
合并成环,就是加一个等差数列。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define M 500010 4 #define LL long long 5 inline int read() { 6 char ch = getchar(); int x = 0, f = 1; 7 while(ch < '0' || ch > '9') { 8 if(ch == '-') f = -1; 9 ch = getchar(); 10 } 11 while('0' <= ch && ch <= '9') { 12 x = x * 10 + ch - '0'; 13 ch = getchar(); 14 } 15 return x * f; 16 } 17 int fa[M], sz[M]; 18 bool vis[M]; 19 LL q[M * 4], A1[4 * M], D[4 * M]; 20 inline int Find(int x) { 21 return fa[x] == x ? x : fa[x] = Find(fa[x]); 22 } 23 inline void update(int l, int r, int o, LL a1, LL d) { 24 int len = r - l + 1; 25 q[o] += (1ll * (a1 + a1 + 1ll * (len - 1) * d) * len / 2ll); 26 A1[o] += a1; D[o] += d; 27 } 28 inline void pushdown(int l, int mid, int r, int o) { 29 LL a1 = A1[o], d = D[o]; 30 if(a1 != 0 || d != 0) { 31 update(l, mid, 2 * o, a1, d); 32 update(mid + 1, r, 2 * o + 1, a1 + 1ll * (mid - l + 1) * d, d); 33 A1[o] = D[o] = 0; 34 } 35 } 36 inline void Add(int l, int r, int o, int x, int y, LL a1, LL d) { 37 if(x <= l && r <= y) { 38 update(l, r, o, a1, d); 39 return; 40 } 41 int mid = (l + r) / 2; 42 pushdown(l, mid, r, o); 43 int Lnum = 0; 44 if(x <= mid) Lnum = min(mid, y) - x + 1; 45 if(x <= mid) Add(l, mid, 2 * o, x, min(mid, y), a1, d); 46 if(y > mid) Add(mid + 1, r, 2 * o + 1, max(mid + 1, x), y, a1 + d * Lnum, d); 47 q[o] = q[2 * o] + q[2 * o + 1]; 48 } 49 inline LL query(int l, int r, int o, int x, int y) { 50 if(x <= l && r <= y) { 51 return q[o]; 52 } 53 int mid = (l + r) / 2; 54 LL ret = 0; 55 pushdown(l, mid, r, o); 56 if(x <= mid) ret += query(l, mid, 2 * o, x, y); 57 if(y > mid) ret += query(mid + 1, r, 2 * o + 1, x, y); 58 return ret; 59 } 60 int main() { 61 int n = read(), m = read(), q = read(); 62 for(int i = 1; i <= n; ++ i) { 63 fa[i] = i; sz[i] = 1; 64 } 65 Add(1, n, 1, 1, 1, n, 0); 66 for(int tt = 1; tt <= m + q; ++ tt) { 67 int op = 1, l, r; 68 if(tt > m) op = read(); 69 l = read(), r = read(); 70 if(op == 1) { 71 if(l == r) continue; 72 if(Find(l) != Find(r)) { 73 int p = Find(l), q = Find(r); 74 int x = sz[p], y = sz[q]; 75 if(sz[p] > sz[q]) swap(p, q); 76 fa[p] = q; sz[q] += sz[p]; 77 if(2 <= min(x, y) + 1) { 78 Add(1, n, 1, 2, min(x, y) + 1, 1, 1); 79 } 80 if(min(x, y) + 2 <= max(x, y) + 1) { 81 Add(1, n, 1, min(x, y) + 2, max(x, y) + 1, min(x, y), 0); 82 } 83 if(max(x, y) + 2 <= x + y) { 84 Add(1, n, 1, max(x, y) + 2, x + y, min(x, y) - 1, -1); 85 } 86 } 87 else { 88 int x = sz[Find(l)]; 89 vis[Find(l)] = 1; 90 if(2 <= x) { 91 Add(1, n, 1, 2, x, 1, 1); 92 } 93 } 94 } 95 else { 96 LL res = query(1, n, 1, l, r); 97 printf("%lld\n", res); 98 } 99 } 100 }