并查集 hdu3038 How Many Answers Are Wrong

来源:互联网 发布:微视频神器软件 编辑:程序博客网 时间:2024/05/22 03:43

传送门:点击打开链接

题意:有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;}


0 0
原创粉丝点击