BZOJ 4551[Tjoi2016&Heoi2016]树(树链剖分+二分)
Description
在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?
Input
输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v
有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询
问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。
Output
输出一个正整数,表示结果
Sample Input
5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3
Sample Output
1
2
2
1
题解:感觉树链剖分的思路还是很好想的,一个点的祖宗肯定在它到根的路径里,我们可以令每个打标记的点权值为一,对于每条完整的链统计区间和,如果大于零,说明这段区间上至少有一个打了标记的点,对于这段区间,求出后一段的前缀和,如果是0,搜索前一段,否则搜索后一段.这是一种二分的思路.
代码如下:
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; struct node
{
int sum,l,r;
}tr[];
int deep[],fa[],size[],son[],w[],iid[],id[],c[],top[],cnt;
vector<int> g[]; void push_up(int root)
{
tr[root].sum=tr[lson].sum+tr[rson].sum;
} void build(int root,int l,int r)
{
if(l==r)
{
tr[root].l=l;
tr[root].r=r;
tr[root].sum=w[l];
return ;
}
tr[root].l=l;
tr[root].r=r;
int mid=(l+r)>>;
build(lson,l,mid);
build(rson,mid+,r);
push_up(root);
} void update(int root,int x,int val)
{
if(x==tr[root].l&&x==tr[root].r)
{
tr[root].sum=val;
return ;
}
int mid=(tr[root].l+tr[root].r)>>;
if(x<=mid)
{
update(lson,x,val);
}
else
{
update(rson,x,val);
}
push_up(root);
} int query(int root,int l,int r)
{
if(l==tr[root].l&&tr[root].r==r)
{
return tr[root].sum;
}
int mid=(tr[root].l+tr[root].r)>>;
if(l>mid)
{
return query(rson,l,r);
}
else
{
if(r<=mid)
{
return query(lson,l,r);
}
}
return query(lson,l,mid)+query(rson,mid+,r);
} void dfs1(int now,int f,int dep)
{
deep[now]=dep;
fa[now]=f;
size[now]=;
int maxson=-;
for(int i=;i<g[now].size();i++)
{
if(g[now][i]==f)
{
continue;
}
dfs1(g[now][i],now,dep+);
size[now]+=size[g[now][i]];
if(maxson<size[g[now][i]])
{
maxson=size[g[now][i]];
son[now]=g[now][i];
}
}
} void dfs2(int now,int topf)
{
id[now]=++cnt;
iid[cnt]=now;
w[cnt]=c[now];
top[now]=topf;
if(!son[now])
{
return;
}
dfs2(son[now],topf);
for(int i=;i<g[now].size();i++)
{
if(g[now][i]==son[now]||g[now][i]==fa[now])
{
continue;
}
dfs2(g[now][i],g[now][i]);
}
} int check(int l,int r)
{
if(l==r)
{
return l;
}
int mid=(l+r)>>;
int tmp=query(,mid+,r);
if(tmp)
{
return check(mid+,r);
}
else
{
return check(l,mid);
}
} int path_query(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
int tmp=query(,id[top[x]],id[x]);
if(!tmp)
{
x=fa[top[x]];
}
else
{
return check(id[top[x]],id[x]);
}
}
if(deep[x]>deep[y])
{
swap(x,y);
}
return check(id[x],id[y]);
} int main()
{
int n,m,vv;
scanf("%d%d",&n,&m);
for(int i=;i<=n-;i++)
{
int from,to;
scanf("%d%d",&from,&to);
g[from].push_back(to);
g[to].push_back(from);
}
c[]=;
dfs1(,,);
dfs2(,);
build(,,n);
char c;
for(int i=;i<=m;i++)
{
scanf("\n%c %d",&c,&vv);
if(c=='C')
{
update(,id[vv],);
}
if(c=='Q')
{
printf("%d\n",iid[path_query(,vv)]);
}
}
}
BZOJ 4551[Tjoi2016&Heoi2016]树(树链剖分+二分)的更多相关文章
- BZOJ 4551: [Tjoi2016&Heoi2016]树
4551: [Tjoi2016&Heoi2016]树 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 748 Solved: 394[Subm ...
- BZOJ 4551 [Tjoi2016&Heoi2016]树 ——并查集
树剖显然可以做. 然而有一种更神奇的方法,并查集+时光倒流. 每个节点指向它上面最近的标记节点,标记节点指向自己,然后删除标记,就可以用并查集查询了. #include <map> #in ...
- BZOJ 4551: [Tjoi2016&Heoi2016]树 并查集(&&图论?)
反向操作,先把所有的标记都打上(记得统计标记的数目),然后依次撤销,合并到自己的上一个点pre,即fa[u]=getf(pre[u]) #include<cstdio> #include& ...
- bzoj 4551: [Tjoi2016&Heoi2016]树【并查集】
看起来像是并查集,但是是拆集合,考虑时间倒流,先把标记都打上,然后把并查集做出来 每次到一个修改点就把这个点的计数s[u]--,当这个s为0时就把这个点和他的父亲合并(因为可能有多次标记) #incl ...
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)
题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...
- hdu4729 树链剖分+二分
An Easy Problem for Elfness Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65535/65535 K (J ...
- NOIP 2015 BZOJ 4326 运输计划 (树链剖分+二分)
Description 公元 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n− 条双向航道,每条航道建立在两个星球之间,这 n− 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司, ...
- BZOJ 4326 树链剖分+二分+差分+记忆化
去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! #include <iostream> #include <cstring> #i ...
- BZOJ.3252.攻略(贪心 长链剖分/线段树)
题目链接 贪心,每次选价值最大的一条到根的链.比较显然(不选白不选). 考虑如何维护这个过程.一个点的价值选了就没有了,而它只会影响它子树里的点,可以用DFS序+线段树修改.而求最大值也可以用线段树. ...
随机推荐
- zabbix的各种键值
zabbix服务器端通过与zabbix agent通信来获取客户端服务器的数据,agent分为两个版本,在配置主机我们可以看到一个是agent,另一个是agent(active). agent:zab ...
- Zabbix常用key和自定义key的讲解
zabbix中常用到的几个key: 1.监控端口的:net.tcp.port[,3306],可以在服务器端对被监控端测试. /usr/local/zabbix/bin/ -s192.168.8.120 ...
- 教你怎么样在大陆直接使用google搜索
一.环境准备 我们需要一个nginx的模块来进行设置,ngx_http_google_filter_module.前提我们是有一个海外的VPS,并且可以访问谷歌,我的VPS是亿速云香港的. 首先先感受 ...
- scrapy---callback 传递自定义参数
在scrapy提交一个链接请求是用 Request(url,callback=func) 这种形式的,而parse只有一个response参数,如果自定义一个有多参数的parse可以考虑用下面的方法实 ...
- 四则运算程序(java基于控制台)
四则运算题目生成程序(基于控制台) 一.题目描述: 1. 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 -o Exercise.txt 将生成10个题目. 2. 使用 -r ...
- Software Engineering-HW8 个人总结
Software Engineering-HW8 个人总结 2017282110264 李世钰 一.请参考第一次作业,当初你对课程的承诺和期望都兑现了吗? 大致实现了.经过了最后的团队项目,基本了解一 ...
- 1013团队Beta冲刺day7
项目进展 李明皇 今天解决的进度 部分数据传递和使用逻辑测试 林翔 今天解决的进度 服务器端查看个人发布的action,修改已发布消息状态的action,仍在尝试使用第三方云存储功能保存图片 孙敏铭 ...
- swift 编写欢迎界面-- ios开发
转载自:http://blog.csdn.net/u014455765/article/details/49622947 现在很多iOS开发人员都从oc转向Swift, swift 也必将成为ios开 ...
- java方法的定义格式
Java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段,声明格式为: [修饰符1 修饰符2 …..] 返回值类型 方法名( 形式参数列表 ){ Java 语句;… … … } 例如 ...
- DML数据操作语言之增加,删除,更新
1.数据的增加 数据的增加要用到insert语句 ,基本格式是: insert into <表名> (列名1,列名2,列名3,......) values (值1,值2,值3,..... ...