首先因为能走过的边的边权是递增的,那么经典套路是枚举最大的边的长度然后用并查集合并图上点的连通性。
按照题意,当困难度为的时候的答案就是将所有边权
的边加进去之后起点所在的连通块中不同类型点的数量。
注意类型数量比较少只有种,所以可以直接对每个并查集用
维护并查集里出现的点的类型情况。
发现有多次询问,只有当加入的边的最大边权变化时获得的愉悦值才会改变,所以先把边权离散化,从小到大枚举加边做前缀和。
具体的设离散化后一共有种边权,将第
小的边加进去之后获得的愉悦值是
,设
表示从最开始到现在获得的愉悦值的前缀和,则
。
这样对于输入的和
有三种情况:
那么答案就是
。
设所有边权中第一个大于等于
的边是第
大的,那么答案是
。
设所有边权中第一个大于等于
的边是第
大的,第一个大于等于
的边是第
大的,那么答案是
;特别的如果
,那么要减去
,加上
。
时间复杂度,其中
是颜色种数。
/* _______ _______ _______ / _____ \ / _____ \ / _____ \ / / \_\ _ __ _ / / \ \ _ __ _ / / \_\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | __ | | | | | | | | | | | | __ \ \ | | / / | | \ \| | \ \ | | / / | | __ \ \_____/ / \ \/ /\ \/ / \ \_____\ / \ \/ /\ \/ / \ \_____/ / \_______/ \___/ \___/ \______/\__\ \___/ \___/ \_______/ */ #include <iostream> #include <algorithm> #include <cstdio> #include <bitset> #include <cstring> using namespace std; const int N = 5e5; #define ll long long int n, m, fa[N + 50], siz[N + 50], c[N + 50], cwq, b[N + 50], q, x, opt, M, s[N + 50]; bitset<600> bit[N + 50]; ll ans[N + 50], lastans = 0; struct Bian { int u, v, w; } line[N + 50]; void Read(int &x) { x = 0; int p = 0; char st = getchar(); while (st < '0' || st > '9') p = (st == '-'), st = getchar(); while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar(); x = p ? -x : x; return; } int Find(int x) { return fa[x] == x ? fa[x] : fa[x] = Find(fa[x]); } void Merge(int u, int v) { int fu = Find(u), fv = Find(v); if (fu == fv) return; if (siz[fu] > siz[fv]) swap(u, v); fa[fu] = fv; siz[fv] += siz[fu]; bit[fv] = bit[fv] | bit[fu]; return; } int Cmp(Bian a, Bian b) { return a.w < b.w; } int main() { Read(n); Read(m); Read(q); Read(x); Read(opt); if (opt == 1) Read(M); for (int i = 1; i <= n; i++) Read(c[i]); for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1, bit[i][c[i] - 1] = 1; for (int i = 1; i <= m; i++) Read(line[i].u), Read(line[i].v), Read(line[i].w), b[++cwq] = line[i].w; sort(b + 1, b + cwq + 1); cwq = unique(b + 1, b + cwq + 1) - b - 1; for (int i = 1; i <= m; i++) line[i].w = lower_bound(b + 1, b + cwq + 1, line[i].w) - b; sort(line + 1, line + m + 1, Cmp); int pos = 1; s[0] = 1; ans[0] = 1; for (int i = 1; i <= cwq; i++) { while (line[pos].w <= i && pos <= m) Merge(line[pos].u, line[pos].v), pos++; s[i] = bit[Find(x)].count(); ans[i] = ans[i - 1] + 1LL * s[i - 1] * (b[i] - b[i - 1] - 1) + s[i]; } int l, r; // for (int i = 0; i <= cwq; i++) printf("%d %d\n", i, ans[i]); while (q--) { Read(l); Read(r); if (opt == 1) { l = (l ^ lastans) % M + 1; r = (r ^ lastans) % M + 1; } if (l > r) swap(l, r); ll answer = 0; int pos1 = lower_bound(b + 1, b + cwq + 1, l) - b, pos2 = lower_bound(b + 1, b + cwq + 1, r) - b; // cout << pos1 << " " << pos2 << endl; if (pos1 == cwq + 1) { printf("%lld\n", lastans = 1LL * (r - l + 1) * s[cwq]); continue; } if (pos2 == cwq + 1) { answer += ans[cwq] - ans[pos1] + s[pos1]; answer += 1LL * (b[pos1] - l) * s[pos1 - 1]; answer += 1LL * s[cwq] * (r - b[cwq]); printf("%lld\n", lastans = answer); continue; } answer += (b[pos1] - l) * s[pos1 - 1]; answer += 1LL * (r - b[pos2 - 1]) * s[pos2 - 1]; answer += ans[pos2 - 1] - ans[pos1] + s[pos1]; if (b[pos2] == r) answer -= s[pos2 - 1], answer += s[pos2]; printf("%lld\n", lastans = answer); } return 0; }