Description
给一个图,有 (m) 条边,如果有一个区间的所有边构成了环,则使该区间内所有边的权值增 (1),求最后每条边的权值
(mleq 2 imes 10^5)
Solution
一个比较好的结论,如果一个区间 ([l,r]) 可以构成环,那么区间([l,r ightarrow m])都可以构成环
然后我们还有一个结论:随着(l) 的增加,(r)不减
这个题就基本做完了……
(LCT) 维护联通一下
考虑每个环对边权值增加的贡献就可以了,维护需要一个二阶差分
(l) 到 (r) 的值增加是一个区间加,然后(r+1) 到 (m)的增加是一个等差数列(公差 (-1) )
手推一下吧,练一练(挺常用但是难写的)
这里博主好好练了练细节(写错一处调半天)……
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 5e5 + 10;
int f[N], c[N][2], st[N], n, ans1[N], ans2[N], ans3[N];
bool r[N];
inline bool notroot(int x) { return c[f[x]][0] == x || c[f[x]][1] == x; }
inline void pushr(int x) {
swap(c[x][0], c[x][1]);
r[x] ^= 1;
return;
}
inline void push_down(int x) {
if (r[x]) {
if (c[x][0])
pushr(c[x][0]);
if (c[x][1])
pushr(c[x][1]);
}
return r[x] = 0, void();
}
inline void rotate(int x) {
int y = f[x], z = f[y], k = (c[y][1] == x), w = c[x][!k];
if (notroot(y))
c[z][c[z][1] == y] = x;
c[x][!k] = y;
c[y][k] = w;
if (w)
f[w] = y;
f[y] = x, f[x] = z;
return;
}
inline void splay(int x) {
int y = x, z = 0;
st[++z] = y;
while (notroot(y)) st[++z] = y = f[y];
while (z) push_down(st[z--]);
while (notroot(x)) {
y = f[x], z = f[y];
if (notroot(y))
rotate((c[y][0] == x) ^ (c[z][0] == y) ? x : y);
rotate(x);
}
return void();
}
inline void access(int x) {
for (int y = 0; x; x = f[y = x]) splay(x), c[x][1] = y;
return;
}
inline void makeroot(int x) {
access(x);
splay(x);
pushr(x);
return;
}
inline int findroot(int x) {
access(x);
splay(x);
while (c[x][0]) push_down(x), x = c[x][0];
splay(x);
return x;
}
inline void split(int x, int y) {
makeroot(x);
access(y);
splay(y);
return;
}
inline void link(int x, int y) {
makeroot(x);
if (findroot(y) != x)
f[x] = y;
return;
}
inline void cut(int x, int y) {
makeroot(x);
if (findroot(y) == x & f[y] == x && !c[y][0])
f[y] = c[x][1] = 0;
return;
}
inline void add(int l, int r, int del, int d) {
if (r < l)
return;
ans3[l] += del;
ans3[l + 1] += d - del;
ans3[r + 1] -= d * (r - l + 1) + del;
ans3[r + 2] += d * (r - l) + del;
return;
}
struct node {
int from, to;
} e[N];
signed main() {
n = read();
for (int i = 1; i <= n; ++i) e[i].from = read(), e[i].to = read();
for (int l = 1, r = 0; l <= n; ++l) {
bool fl = 0;
while (r < n) {
++r;
if (findroot(e[r].from) == findroot(e[r].to)) {
fl = 1;
break;
}
link(e[r].from, e[r].to);
}
if (fl) {
add(l, r, n - r + 1, 0);
add(r + 1, n, n - r, -1);
r--;
} else
break;
cut(e[l].from, e[l].to);
}
for (int i = 1; i <= n; ++i) ans2[i] = ans2[i - 1] + ans3[i];
for (int i = 1; i <= n; ++i) ans1[i] = ans1[i - 1] + ans2[i],printf("%lld ", ans1[i]);
return 0;
}
} // namespace yspm
signed main() { return yspm::main(); }