P4092 [HEOI2016/TJOI2016]树

题目链接:https://www.luogu.org/problem/P4092

感觉这个题目和前面做的黑白染色的很像,思路都是差不多的吧。

  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <string>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <math.h>
  9 #include <map>
 10
 11 #define LL long long
 12 #define INF 0x3f3f3f3f
 13 using namespace std;
 14 const int maxn = 2e5 + 10;
 15
 16 struct Edge{
 17     int to,next;
 18 }edge[maxn*2];
 19
 20 int tot,head[maxn];
 21
 22 void add_edge(int u,int v){
 23     edge[++tot] = Edge{v,head[u]};
 24     head[u] = tot;
 25 }
 26
 27 int fa[maxn];
 28 int dep[maxn];
 29 int siz[maxn];
 30 int son[maxn];
 31
 32 void dfs1(int u,int f){
 33     fa[u] = f;
 34     dep[u] = dep[f] + 1;
 35     siz[u] = 1;
 36     int maxsize = -1;
 37     for (int i=head[u];~i;i=edge[i].next){
 38         int v = edge[i].to;
 39         if (v == f)
 40             continue;
 41         dfs1(v,u);
 42         siz[u] += siz[v];
 43         if (siz[v] > maxsize){
 44             son[u] = v;
 45             maxsize = siz[v];
 46         }
 47     }
 48 }
 49
 50 int tim;
 51 int dfn[maxn];
 52 int w[maxn];
 53 int top[maxn];
 54
 55 void dfs2(int u,int t){
 56     dfn[u] = ++tim;
 57     top[u] = t;
 58     w[tim] = u;
 59     if (!son[u])
 60         return ;
 61     dfs2(son[u],t);
 62     for (int i=head[u];~i;i=edge[i].next){
 63         int v = edge[i].to;
 64         if (v == fa[u] || v == son[u])
 65             continue;
 66         dfs2(v,v);
 67     }
 68 }
 69
 70 struct segment_tree{
 71     int l,r;
 72     int val;
 73 }tree[maxn*4];
 74
 75 void pushup(int nod){
 76     tree[nod].val = max(tree[nod<<1].val,tree[(nod<<1)+1].val);
 77 }
 78
 79 void build(int l,int r,int nod){
 80     tree[nod].l = l;
 81     tree[nod].r = r;
 82     if (l == r){
 83         tree[nod].val = 1;
 84         return ;
 85     }
 86     int mid = (l + r) >> 1;
 87     build(l,mid,nod<<1);
 88     build(mid+1,r,(nod<<1)+1);
 89     pushup(nod);
 90 }
 91
 92 void modify(int x,int y,int k=1){
 93     int l = tree[k].l,r = tree[k].r;
 94     if (x <= l && y >= r){
 95         tree[k].val = l;
 96         return ;
 97     }
 98     int mid = (l + r) >> 1;
 99     if (x <= mid){
100         modify(x,y,k<<1);
101     }
102     if (y > mid){
103         modify(x,y,(k<<1)+1);
104     }
105     pushup(k);
106 }
107
108 int query(int x,int y,int k=1){
109     int l = tree[k].l,r = tree[k].r;
110     if (x <= l && y >= r){
111         return tree[k].val;
112     }
113     int mid = (l + r) >> 1;
114     int ret = 0;
115     if (x <= mid){
116         ret = max(ret,query(x,y,k<<1));
117     }
118     if (y > mid){
119         ret = max(ret,query(x,y,(k<<1)+1));
120     }
121     return ret;
122 }
123
124 int query_from(int x,int y){
125     int ret = 0;
126     while (top[x] != top[y]){
127         if (dep[top[x]] < dep[top[y]])
128             swap(x,y);
129         ret = max(ret,query(dfn[top[x]],dfn[x]));
130         x = fa[top[x]];
131     }
132     if (dep[x] > dep[y])
133         swap(x,y);
134     ret = max(ret,query(dfn[x],dfn[y]));
135     return ret;
136 }
137
138 int main(){
139     int n,m;
140     scanf("%d%d",&n,&m);
141     memset(head,-1, sizeof(head));
142     for (int i=1;i<=n-1;i++){
143         int x,y;
144         scanf("%d%d",&x,&y);
145         add_edge(x,y);
146         add_edge(y,x);
147     }
148     dfs1(1,0);
149     dfs2(1,1);
150     build(1,n,1);
151     while (m--){
152         int x;
153         char op[4];
154         scanf("%s%d",op,&x);
155         if (op[0] == ‘C‘){
156             modify(dfn[x],dfn[x]);
157         }
158         else {
159             int val = query_from(1,x);
160             printf("%d\n",w[val]);
161         }
162     }
163     return 0;
164 }

原文地址:https://www.cnblogs.com/-Ackerman/p/11469932.html

时间: 2024-10-30 05:06:57

P4092 [HEOI2016/TJOI2016]树的相关文章

[HEOI2016/TJOI2016]树

来一发大暴力 树链剖分无疑了 对于某个询问节点,二分答案所在的深度,若该深度到该节点上的区间和>0,说明其中有满足条件的点,增加深度继续二分,否则减小深度 线段树上的操作:单点修改+区间查询(区间和) 关于时间: 时间复杂度\(O(nlog^{2}n)\) 虽然不是最优解法,但能过了,稍微卡一下,总时间大概900ms,最大点300ms,如果\(O(nlogn)\)的玩家太注重卡常的话还是可以碾的,当然我的代码还有优化余地...(比如传参部分可以用空间换时间,卡常玩家可以尝试一下(还有fread之

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]排序 题意 给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种, 0 l r 表示将区间 \([l,r]\) 的数升序排序. 1 l r 表示将区间 \([l,r]\) 的数降序排序. 询问 \(m\) 次操作后下标为 \(q\) 的数字. 思路 不看题解打死也想不出来系列 考虑二分答案. 设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数

[Luogu 4092] HEOI/TJOI2016 树

[Luogu 4092] HEOI/TJOI2016 树 <题目链接> 搜了树剖标签不知道怎么就跳出了个暴搜题啊! 管他既然做了就发上来吧- 有修改标签就向下搜并修改,遇到标签即停止. 这题是真的真的短. #include <cstdio> #include <queue> using std::queue; const int MAXN=100010; bool flag[MAXN]; int n,q,cnt,head[MAXN],top[MAXN]; struct

bzoj4551【TJOI2016&amp;HEOI2016】树

4551: [Tjoi2016&Heoi2016]树 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 380  Solved: 234 [Submit][Status][Discuss] Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个 结点,可以打多次标记.)2

[HEOI2016&amp;TJOI2016] 排序(线段树)

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2703  Solved: 1386[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,

BZOJ4553: [Tjoi2016&amp;Heoi2016]序列 树套树优化DP

把pos[i]上出现的平常值定义为nor[i]最大值定义为max[i]最小值定义为min[i],那么我们发现在两个值,i(前),j(后),当且仅当max[i]<=nor[j],nor[i]<=min[j]时才会组成序列的前后两个值,并且当序列里所有连续的两个值都满足这个条件是时就可以,因此我们以f[i]表示以i为起点的序列最长值,那么我们就可以转移了f[i]=maxf[j](max[i]<=nor[j],nor[i]<=min[j],pos[i]<pos[j])+1,这就是一

【线段树合并】【P2824】 [HEOI2016/TJOI2016]排序

Description 给定一个长度为 \(n\) 的排列,有 \(m\) 次操作,每次选取一段局部进行升序或降序排序,问你一波操作后某个位置上的数字是几 Hint \(1~\leq~n,~m~\leq~10^5\) Solution 有两种做法,一种在线一种离线,这里把在线部分讲得更清楚点吧-- 考虑离线算法,我们二分该位置上的答案,将大于该数的元素置为 \(1\),小于该数的元素置为 \(0\),然后模拟所有的排序并检验.由于使用线段树对 \(0/1\) 序列多次局部排序可以做到 \(O(m

【BZOJ 4551】【TJOI2016】【HEOI2016】树

http://www.lydsy.com/JudgeOnline/problem.php?id=4551 题目描述 给定一棵有根树(根为 1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先). 输入格式 输入第一行两个正整数 和 分别表示节点个数和操作次数接下来 行,每行两个正整数   表示 到 有一条有向边接下来 行," &q