传送门:点击打开链接
题意:有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; }