https://codeforces.com/contest/893/problem/F

题意:

  给一个有根树,

  多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的一个

  查询强制在线

题解:

  显然,暴力就是,对于每次搜索深搜距离x小于$k$的所有点搜索

  那么我们考虑优化

  首先,查询对$x$距离小于$k$的所有点,等价于在整颗树上,查询$\forall dep(x)≤dep(i)≤dep(x)+k$中,在$x$子树中的点的最小值

  那么,一个大胆的想法就是,对于每个点,用深度去维护区间$[1,n]$,区间信息则为x的子树中,深度$[l,r]$中节点的最小值

  显然,每个点如果真的开了一个线段树,有两个问题

  1.空间是$O(n^2logn)$

  2.时间是$O(n^2logn)$

  但显然的,本题的询问一定程度上,满足区间加法

  或者说,其父亲的信息为其子树信息的"和",

  那么我们可以用动态开点线段树+线段树合并的方式

    而对于任意的合法询问,动态开点线段树中,也一定在建树的过程中被建立过了(儿子被合并到父亲中了)

  空间复杂度降低到$O(nlogn^2)$,时间复杂度降低到$O(nlogn)$

  

#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
using namespace std;
int casn,n,m,k;
const int maxn=1e5+7,maxm=1e7+7;
const ll INF=0x3f3f3f3f3f3f3f;
class graph{public:
struct edge{
int from,to;ll cost;
edge(int a,int b,ll c){from=a,to=b,cost=c;}
};
vector<vector<edge>> node;
int ud=0;
graph(int n=maxn,int f=0){node.resize(n+2);ud=f;}
void add(int a,int b,int c=1){node[a].emplace_back(a,b,c);if(ud)node[b].emplace_back(b,a,c);}
};
class dsegtree{public:
#define nd node[now]
#define ndl node[node[now].son[0]]
#define ndr node[node[now].son[1]]
struct dsegnode {
int son[2];ll val;
dsegnode(){val=INF;}
dsegnode(int x){son[0]=son[1]=0;}
void update(ll x){val=x;}
};
vector<dsegnode> node;
vector<int> root;
int cnt,n,s,t,pos;
dsegtree(int nn,int size=maxm){
n=nn,cnt=0;
node.resize(size);
root.resize(n+2);
}
void pushup(int now){nd.val=min(ndl.val,ndr.val);}
void pushdown(int now){}
void change(int p,ll x,int now){
pos=p;
if(!root[now]) root[now]=++cnt;
update(1,n,x,root[now]);
}
void update(int l,int r,ll x,int now){
if(pos>r||pos<l) return ;
if(l==r){
nd.update(x);
return ;
}
if(!nd.son[0]) nd.son[0]=++cnt;
if(!nd.son[1]) nd.son[1]=++cnt;
pushdown(now);
update(l,(l+r)>>1,x,nd.son[0]);
update(((l+r)>>1)+1,r,x,nd.son[1]);
pushup(now);
}
void unite(int a,int b){root[a]=merge(root[a],root[b]);}
int merge(int a,int b){
if(!a||!b) return a^b;
int now=++cnt;
nd.son[0]=merge(node[a].son[0],node[b].son[0]);
nd.son[1]=merge(node[a].son[1],node[b].son[1]);
nd.val=min(node[a].val,node[b].val);
return now;
}
ll query(int ss,int tt,int now){s=ss,t=tt;return count(1,n,root[now]);}
ll count(int l,int r,int now){
if(s>r||t<l) return INF;
if(s<=l&&t>=r) return nd.val;
return min(count(l,(l+r)>>1,nd.son[0]),count(((l+r)>>1)+1,r,nd.son[1]));
}
};
int main() {
IO;
ll n,m,root;
cin>>n>>root;
vector<int> dep(n+7,0);
vector<ll> val(n+7);
rep(i,1,n) cin>>val[i];
graph g(n,1);
register ll a,b;
rep(i,2,n){
cin>>a>>b;
g.add(a,b);
}
dsegtree tree(n);
auto dfs=[&tree,&g,&val,&dep](auto &&dfs,int now,int pre=-1,int dis=1)->void{
dep[now]=dis;
tree.change(dis,val[now],now);
for(auto &i:g.node[now]){
if(i.to==pre) continue;
dfs(dfs,i.to,now,dis+1);
tree.unite(now,i.to);
}
};
dfs(dfs,root);
cin>>m;
ll x=0,last=0,k=0;
while(m--){
cin>>a>>b;
x=(a+last)%n+1,k=(b+last)%n;
last=tree.query(dep[x],dep[x]+k,x);
cout<<last<<endl;
}
return 0;
}

codeforces 893F - Physical Education Lessons 动态开点线段树合并的更多相关文章

  1. codeforces 915E - Physical Education Lessons 动态开点线段树

    题意: 最大$10^9$的区间, $3*10^5$次区间修改,每次操作后求整个区间的和 题解: 裸的动态开点线段树,计算清楚数据范围是关键... 经过尝试 $2*10^7$会$MLE$ $10^7$会 ...

  2. CF915E Physical Education Lessons 动态开点线段树

    题目链接 CF915E Physical Education Lessons 题解 动态开点线段树 代码 /* 动态开点线段树 */ #include<cstdio> #include&l ...

  3. [Vani有约会]雨天的尾巴——树上差分+动态开点线段树合并

    题目描述 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所 ...

  4. [HDU5709]Claris Loves Painting(动态开点线段树+合并)

    题意:有n(<=1e5)个点的树,每个点都有颜色(颜色可能重复),有m(<=1e5)个询问,每次询问(x,d)问在x的子树中,与x的距离不超过d的节点有多少种不同的颜色.强制要求在线. 分 ...

  5. Physical Education Lessons CodeForces - 915E (动态开点线段树)

    Physical Education Lessons CodeForces - 915E This year Alex has finished school, and now he is a fir ...

  6. Codeforces 915E Physical Education Lessons

    原题传送门 我承认,比赛的时候在C题上卡了好久(最后也不会),15min水掉D后(最后还FST了..),看到E时已经只剩15min了.尽管一眼看出是离散化+线段树的裸题,但是没有时间写,实在尴尬. 赛 ...

  7. CF915E Physical Education Lessons(珂朵莉树)

    中文题面 据说正解是动态开点线段树而且标记也不难下传的样子 然而这种区间推平的题目还是喜欢写珂朵莉树啊……码量小…… 虽然真要构造的话随便卡…… //minamoto #include<cstd ...

  8. Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

    思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 els ...

  9. CodeForces - 915E 动态开点线段树

    题目 晚上有n个亮着的灯泡,标号从1到n. 现在存在2种操作,如下: 操作1,关掉标号 [l,r] 区间的灯 操作2,打开标号 [l,r] 区间的灯 下面有q次询问,每次询问执行其中一种操作,询问格式 ...

随机推荐

  1. 线性回归和Logistic回归

    目录 线性回归 用线性回归模型拟合非线性关系 梯度下降法 最小二乘法 线性回归用于分类(logistic regression,LR) 目标函数 如何求解\(\theta\) LR处理多分类问题 线性 ...

  2. JS 禁止Ctrl+C + 禁止右键操作

    <script type="text/javascript"> document.oncontextmenu = new Function("return f ...

  3. SpringCloud(2)服务消费者(rest+ribbon)

    1.准备工作 这一篇文章基于上一篇文章的工程.启动eureka-server 工程,端口为 8761.分别以端口 8762 和 8763 启动 service-hi 工程.访问 localhost:8 ...

  4. Asp.Net Core SignalR 用泛型Hub优雅的调用前端方法及传参

    继续学习 最近一直在使用Asp.Net Core SignalR(下面成SignalR Core)为小程序提供websocket支持,前端时间也发了一个学习笔记,在使用过程中稍微看了下它的源码,不得不 ...

  5. 树的平衡之AVL树——错过文末你会后悔,信我

    学习数据结构应该是一个循序渐进的过程: 当我们学习数组时,我们要体会数组的优点:仅仅通过下标就可以访问我们要找的元素(便于查找). 此时,我们思考:假如我要在第一个元素前插入一个新元素?采用数组需要挪 ...

  6. iview库表table组件内嵌套Select组件

    表格内render函数渲染Select组件   { title: '属性值', key: 'values', render:(h,params)=>{ return h('Select',{   ...

  7. Java 创建一个简单的验证码图片

    代码如下: package lixin.gan.test; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2 ...

  8. VS界面控件大小调整

    vs2015 ,配置名称显示不全,怎么才能把这个搞宽? 这个问题困扰时间挺长了, 对vs的应用仅限于敲代码.编译, 其他的功能了解甚少, 于是试着在右键菜单中找到了界面自定义窗口, 如下: 找到想要修 ...

  9. POJ3565 Ants (不相交线)

    那请告诉我 A - D  B - C  和  A - C  B - D 那个的和小 显然是A - C  B - D  (可以根据四边形 对角线大于对边之和) 然后 求的答案是不是就一定是不相交的 就是 ...

  10. leetcode-884两句话中的不常见单词

    ''' 给定两个句子 A 和 B . (句子是一串由空格分隔的单词.每个单词仅由小写字母组成.) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的. 返回所有 ...