传送门:点击打开链接
题意:有Q次操作,每次操作告诉你l,r,s,表示区间[l,r]里的和为s。如果某次操作与之前得到的内容冲突,就无视这次操作,最后输出冲突的操作次数。
思路:首先我们可以证明,只有当[l,r]存在多种情况被小区间恰好覆盖时,然后多种情况的小区间之和不相等时,就认为是冲突的。
我们能比较容易的想到把l-1,和r去维护并查集,但是如何维护s,是个问题
如果按秩合并,我们可以用边长来维护额外的信息,但是按秩合并的边,维护的信息,是最后两个连通块合并时的信息。
而且通常会与lca和路径求和结合起来,如果非要强行做这道题,那就是lct了,或者按秩合并+离线lca也能搞。
实际上,并不需要这么复杂的编程。
我们来维护节点到树根的距离。那么对于一棵树上面的两个节点,如果这棵树的根接到了其他的树上,他们的距离可能会变化。
但是,他们到树根距离的差,是不会变的!所以我们这里来维护节点到树根的距离,利用他们的相减是恒定的,来维护答案。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;const int MX = 2e5 + 5;
int P[MX], val[MX];
int find(int x) {if(P[x] == x) return x;int p = find(P[x]);val[x] += val[P[x]];return P[x] = p;
}
int solve(int l, int r, int s) {int u = find(l), v = find(r);if(u != v) {P[v] = u; val[v] = s + val[l] - val[r];return 0;} else return s != val[r] - val[l];
}
int main() {int n, m; //FIN;while(~scanf("%d%d", &n, &m)) {for(int i = 0; i <= n; i++) {P[i] = i; val[i] = 0;}int ans = 0;for(int i = 1; i <= m; i++) {int l, r, s;scanf("%d%d%d", &l, &r, &s); l--;ans += solve(l, r, s);}printf("%d\n", ans);}return 0;
}