2019牛客暑期多校训练营(第八场)I-Inner World DFS序+主席树(扫描线也可)
题意:初始有n棵树,每棵树都只有1个n号节点,现在有m次添加操作,每次操作是将$[l,r]$范围内的树的$u$节点后面添加一个$v$节点。每个v节点只会被添加一次。
然后是q次询问,输出$[l,r]$范围内的树$x$节点的子树大小之和。
思路:由于每个节点被当成子节点添加到树上只会被添加一次,所以假设直接将节点连到一棵树上,按照dfs排序之后,x节点的子树dfs序必定是连续的。
考虑主席树,我们以dfs序为主席树的版本,每个节点就让$(ql,qr)$之间的树加一,最后只需要将ou[x]和in[x]-1这两个版本之间的主席树相减即可。(代码在最下方)
另一个做法:考虑扫描线,我们还是先处理处dfs序,对于节点x的求解,我们可以分解成,减去x之前所有节点(ql,qr)的值,再加上ou[x]的(ql,qr)的值,就得到了我们要的答案。所以我们还是按dfs序处理线段树,将每一个节点的影响加入线段树后,再处理这个节点需要加减的地方即可。我自己没有写过扫描线版本,此处引用一位朋友的代码。
//这是扫描线的关键,此处的线段树就是一个普通的区间求和的线段树。
scanf("%d", &q);
for(int i = ; i <= q; i++) {
int x, l, r;
scanf("%d%d%d", &x, &l, &r);
V[in[x] - ].push_back(Qus{-, l, r, i});
V[ot[x]].push_back(Qus{, l, r, i});
}
for(int i = ; i <= idx; i++) {
Tree.update(L[rk[i]], R[rk[i]], , , n, );
for(auto t : V[i]) {
ans[t.id] += t.op * Tree.query(t.l, t.r, , n, );
}
}
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,b,a) for(int i=b;i>=a;i--)
#define clr(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pii pair<int,int >
using namespace std;
typedef long long ll;
ll rd()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
const int inf=0x3f3f3f3f;
int n,m,q,tot,root[maxn],l[maxn],r[maxn],in[maxn],ou[maxn],re[maxn],ti;
struct node{
int l,r;
ll sum,lazy;
}tr[maxn*];
vector<int >ve[maxn];
void dfs(int u){
in[u]=++ti;
re[ti]=u;
for(auto it:ve[u]){
dfs(it);
}
ou[u]=ti;
}
void update(int &rt,int pre,int l,int r,int ql,int qr,ll val){
tr[rt=++tot]=tr[pre];
tr[rt].sum+=(qr-ql+)*val;
if(ql<=l&&r<=qr){
tr[rt].lazy+=val;
return;
}
int mid=(l+r)>>;
if(ql<=mid)update(tr[rt].l,tr[pre].l,l,mid,ql,min(qr,mid),val);
if(mid<qr)update(tr[rt].r,tr[pre].r,mid+,r,max(mid+,ql),qr,val);
}
ll query(int rt,int pre,int l,int r,int ql,int qr,ll add){
if(ql<=l&&r<=qr){
return tr[rt].sum-tr[pre].sum+(r-l+)*add;
}
add+=tr[rt].lazy-tr[pre].lazy;
int mid=(l+r)>>;
ll res=;
if(ql<=mid)res+=query(tr[rt].l,tr[pre].l,l,mid,ql,qr,add);
if(mid<qr)res+=query(tr[rt].r,tr[pre].r,mid+,r,ql,qr,add);
return res; }
int main(){
cin>>n>>m;
l[]=,r[]=n;
for(int i=;i<=m;i++){
int u,v,x,y;
u=rd(),v=rd(),x=rd(),y=rd();
ve[u].pb(v);
l[v]=x,r[v]=y;
}
dfs();
for(int i=;i<=ti;i++){
int u=re[i];
update(root[i],root[i-],,n,l[u],r[u],);
}
cin>>q;
rep(i,,q){
int x,ql,qr;
x=rd(),ql=rd(),qr=rd();
printf("%lld\n",query(root[ou[x]],root[in[x]-],,n,ql,qr,));
}
}
2019牛客暑期多校训练营(第八场)I-Inner World DFS序+主席树(扫描线也可)的更多相关文章
- 2019牛客暑期多校训练营(第九场)H Cutting Bamboos(主席树+二分)
题意:n个竹子,有高度,q次询问,询问之间是独立的,每次查询输入l,r,x,y代表砍区间[l,r]]内的竹子砍y次,最后一次要砍成0,每次砍掉的总长度相同,问第x次砍的高度是多少. 既然每次要求砍掉的 ...
- 2019牛客暑期多校训练营(第一场)I Points Division(dp+线段树优化)
给你n个点,第i个点在的位置为(xi,yi),有两个属性值(ai,bi).现在让你把这n个点划分为A和B两个部分,使得最后不存在i∈A和j∈B,使得xi>=xj且yi<=yj.然后对于所有 ...
- 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
- 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...
- 2019牛客暑期多校训练营(第一场) B Integration (数学)
链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...
- 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...
- 2019牛客暑期多校训练营(第二场)F.Partition problem
链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...
- 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- 2019牛客暑期多校训练营(第二场)J-Subarray(思维)
>传送门< 前言 这题我前前后后看了三遍,每次都是把网上相关的博客和通过代码认真看了再思考,然并卵,最后终于第三遍也就是现在终于看懂了,其实懂了之后发现其实没有那么难,但是的的确确需要思维 ...
随机推荐
- 剑指offer——64和为s的数字
题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. 题解 ...
- MySQL数据库(一)—— 数据库介绍、MySQL安装、基础SQL语句
数据库介绍.MySQL安装.基础SQL语句 一.数据库介绍 1.什么是数据库 数据库即存储数据的仓库 2.为什么要用数据库 (1)用文件存储是和硬盘打交道,是IO操作,所以有效率问题 (2)管理不方便 ...
- Android Telephony分析(七) ---- 接口扩展(异步转同步)
本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...
- socket API CSocket CAsyncSocket 用法及区别
要进行网络编程就要和Socket打交道,Socket有同步阻塞方式和异步非阻塞方式两种使用,事实上同步和异步在我们编程的生涯中可能遇到了很多,而Socket也没什么特别.虽然同步好用,不费劲,但不能满 ...
- VIM查找空格
匹配1到多个空格 /\s\+ 或者开启very magic模式 /\v\s+
- VUE 中 使用 iview Form组件 enter键防止页面刷新
<Form :label-width="100" inline label-position='left' @keydown.native.enter.prevent =&q ...
- Linux 父子进程实现复制文件内容到另一个文件内
1. 子进程先拷贝前一半 ,父进程一直阻塞到子进程拷贝完再拷贝后一半 /* 子进程先拷贝前一半文件,父进程先阻塞等待子进程拷贝完前一半内容, * 然后父进程在拷贝,后一半内容 * */ #includ ...
- linux常用命令-3文件与目录相关命令
cd .. #返回上一级目录 cd ../.. #返回上两级目录 cd - #返回上次所在目录 cp file1 file2 #将file1复制为file2 cp -a dir1 dir2 #复制一个 ...
- 普通浏览器实现点击打开微信app
给予点击事件,然后调用以下方法即可(我这用的是jq的点击): $(function() { Cz.Alert().success({text: '请返回公众号查看充值结果'}); $(".a ...
- margin与padding
1.不加内边距的div: <div style="width:150px; height:150px; "> <div style="width: ...