一道并查集的题目硬是被我当成线段树写了,感觉这样写虽然不是最好的,不过能a就行

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=103906#problem/G

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2170

首先题意:

一个可以被标记的树,起初只有根节点被标记了,然后有两种操作,第一种操作是把某一个点标记,第二个操作是询问他的祖先中离他最近的节点编号,最后出书询问的节点编号和.

这是我在并查集专题上面遇到的,不过第一反应暴力肯定不行(然而暴力的并查集查找祖先也可以过...),然后想半天没思路,因为当前节点的询问过后不能直接路径压缩,因为这样后面如果该条路径有一个点被标记那就gg了

但此时想法是如果这个点被标记了,那么他的后代可能都会受到影响,但是又不能一个一个去更新影响,想到这里再加上题目中的两种操作更新查询和线段树神似,所以就开始搞线段树,但是这里有一个问题:线段树更新的点都在一起...,接着想到以前一道没做出来的题(翻硬币类似的)用了dfsn重建树然后再更新维护,所以就用先序遍历了一下,同时我记录下了每个节点的深度,因为更新的时候,深度更深的点应该把深度浅的点信息更新掉(为啥?举一个抽象例子,如果点A被B和C更新了,那么肯定B和C是A的祖先,如果depB<depC,那么depC离A更近)

其他的都是细节问题了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <cstdlib>
#include <algorithm>
#include <stack>
#include <map>
#include <queue>
#include <vector> using namespace std;
const int maxn = 1e5+100;
const int INF = 0x3f3f3f3f;
#define pr(x) // cout << #x << " = " << x << " ";
#define prln(x) // cout << #x << " = " << x <<endl;
#define ll long long
int head[maxn], nxt[maxn], to[maxn], dfsn, cnt, id[maxn], r[maxn], _n, sum[maxn<<2], dep[maxn];
//建最初的树
void addedge(int u, int v) {
nxt[cnt] = head[u];
head[u] = cnt;
to[cnt++] = v;
}
//线段树等初始化
void init(int n) {
cnt = dfsn = 0;
_n = 1;
while(_n < n) _n = _n*2;
int _nn = _n*2;
for(int i = 0; i <= _nn; ++i) sum[i] = -1;
for(int i = 0; i <= n;++i) {
head[i] =-1;
}
}
//dfs建树
//这里保证了一个点的后代都在一起被访问到,最左边的点是这个点id[u]表示最左边点//的编号,r[u]表示u后代最右边点编号
void dfstree(int fa,int u) {
id[u] = ++dfsn;
dep[u] = dep[fa]+1;
for(int i = head[u]; ~i; i = nxt[i]){
dfstree(u,to[i]);
}
r[u] = dfsn;
}
//这里是线段树的更新操作
//sum初始化为-1,如果当前未被更新或者更新的点深度小于v2这个点深度,,那么更新
inline void getans(int& ans, const int& v2){
if(ans == -1 || dep[ans] < dep[v2]) ans = v2;
}
//其他和正常线段树都一样了
void pushdown(int rt) {
if(sum[rt] != -1) {
getans(sum[rt<<1], sum[rt]);
getans(sum[rt<<1|1],sum[rt]);
}
}
void update(int rt, int l, int r, int ql, int qr, int v) {
if(ql <= l && r <= qr) {
getans(sum[rt], v);
return;
}
pushdown(rt);
int m = l + r >> 1;
if(m >= ql) update(rt<<1, l, m, ql, qr, v);
if(m < qr) update(rt<<1|1, m+1, r, ql, qr, v);
}
//这里查询稍微改了一下,直接向上找
int query(int rt) {
rt += _n-1;
int ans = 0;
while(rt>=1) {
getans(ans,sum[rt]);
rt = rt>>1;
}
return ans;
}
int main(){
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
//freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int n, m, x;
char op[10];
while(cin >> n >> m && (n||m)) {
ll ans = 0;
init(n);
for(int i = 2; i <= n; ++i) {
scanf("%d", &x);
addedge(x,i);
}
dep[0] = 0;
dfstree(0,1);
update(1, 1, _n, id[1], r[1], 1);
for(int i = 0; i < m; ++i) {
scanf("%s%d", op, &x);
if(op[0] == 'M') update(1, 1, _n, id[x], r[x], x);
else ans += query(id[x]);
}
printf("%lld\n", ans);
}
return 0;
}

Marked Ancestor的更多相关文章

  1. AOJ 2170 Marked Ancestor (基础并查集)

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=45522 给定一棵树的n个节点,每个节点标号在1到n之间,1是树的根节点,有如 ...

  2. Aizu 2170 Marked Ancestor

    题意:出一颗树,有两种操作:1. mark  u  标记结点u2.query  u  询问离u最近的且被标记的祖先结点是哪个让你输出所有询问的和. 思路:数据量太小,直接暴力dfs就可以了 #incl ...

  3. Marked Ancestor [AOJ2170] [并查集]

    题意: 有一个树,有些节点染色,每次有两种操作,第一,统计该节点到离它最近的染色父亲结点的的号码(Q),第二,为某一个节点染色(M),求第一种操作和. 输入: 输入由多个数据集组成.每个数据集都有以下 ...

  4. Aizu2170 Marked Ancestor(并查集)

    https://vjudge.net/problem/Aizu-2170 并查集用于管理元素分组情况. 建树pre[]记录父节点,一开始只有结点1被标记了,所以find()最终得到的根都是1. 如果遇 ...

  5. AOJ 2170 Marked Ancestor[并查集][离线]

    题意: 给你一颗N个节点的树,节点编号1到N.1总是节点的根.现在有两种操作: M v: 标记节点v Q v: 求出离v最近的标记的相邻节点.根节点一开始就标记好了. 现在给一系列操作,求出所有Q操作 ...

  6. Aizu 2170 Marked Ancestor(并查集变形)

    寻找根节点很容易让人联想到DisjointSet,但是DisjointSet只有合并操作, 所以询问离线倒着考虑,标记会一个一个消除,这时候就变成合并了. 因为询问和查询的时间以及标记生效的时间有关, ...

  7. Aizu:2170-Marked Ancestor

    Marked Ancestor Time limit 8000 ms Memory limit 131072 kB Problem Description You are given a tree T ...

  8. ProgrammingContestChallengeBook

    POJ 1852 Ants POJ 2386 Lake Counting POJ 1979 Red and Black AOJ 0118 Property Distribution AOJ 0333 ...

  9. mysq l错误Table ‘./mysql/proc’ is marked as crashed and should be repaired

    续上一篇,解决了上一篇中的问题后,启动成功,但是在数据库中操作会存在一些问题,一些操作报一下异常: Table './mysql/proc' is marked as crashed and shou ...

随机推荐

  1. Redis 实战之主从复制、高可用、分布式

      目录 简介 持久化 主从复制 高可用 Redis-Sentinel .NET Core开发 分布式 Redis-Cluster 配置说明 常见问题 简介 本节内容基于 CentOS 7.4.170 ...

  2. node.js 实现 AES CTR 加解密

    node.js 实现 AES CTR 加解密 node aesctr 前言 由于最近我们在做一款安全的文件分享 App, 所有文件均需要使用 aes ctr 来进行加密,aes key 还有一整套完整 ...

  3. Codeforces Round #568 (Div. 2) C2. Exam in BerSU (hard version)

    链接: https://codeforces.com/contest/1185/problem/C2 题意: The only difference between easy and hard ver ...

  4. 解决 Failed to start LSB: Bring up/down networking 问题

    我用的是虚拟机,一换网络环境虚拟机的ip就没有了,重启网上就报Failed to start LSB: Bring up/down networking错误.网上查了一圈说什么HWADDR有问题,改了 ...

  5. ETL工具之kittle使用案例整理

    主花了一下午时间,收集全网,学习了下kittle,觉得该大v写的不错,特意整理给大家!学会这几个案例kittle基本就没问题了. 1.kettle案例一抽取gz格式文本内容保存到mongodb  ht ...

  6. layui.form is not a function

    改变: var form = layui.form; 如果你是从1.x升级2.x造成的,那只需要在定义的时候吧后面的()去掉就可以了.请关注更新日志:1.x 升 2.0 特别注意事项layDate日期 ...

  7. 配置文件:mainfest.xml

    AndroidManifest.xml 是每个android程序中必须的文件.   它位于整个项目的根目录,描述了package中暴露的组件(activities,services, 等等),他们各自 ...

  8. tensorflow的变量作用域

    一.由来 深度学习中需要使用大量的变量集,以往写代码我们只需要做全局限量就可以了,但在tensorflow中,这样做既不方便管理变量集,有不便于封装,因此tensorflow提供了一种变量管理方法:变 ...

  9. Android中实现双击(多击)事件

    要实现双击,你需要保存第一次点击时的时间,需要使用到变量,之后便是与第二次点击时的时间比较,看时间间隔是否在你设定的时间内(比如500ms). ? 1 2 3 4 5 6 7 8 9 10 11 12 ...

  10. (三)mysql -- 逻辑控制

    条件控制 CASE validity_date THEN '月' THEN '年' ELSE '季' END CASE THEN '月' THEN '年' ELSE '季' END 循环控制 待补充