2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)
题目背景
SOURCE:NOIP2015-GDZSJNZX(难)
题目描述
学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演。其中第 i 个节目的表演时间为第 i 个单位时间,表演的舞台为 Ai ,注意可能有多个节目使用同一个舞台。作为 Tom 的忠实粉丝之一的 Alice,当然要来逛一下啦,顺便看一下能不能要到 Tom 的签名。
Alice 一开始会先在 A1 看完节目1再去闲逛。
Alice 可以在舞台之间随便乱走。但是假如 Alice 当前在看第 i 个节目,站在第 Ai 个舞台前面的话,由于有些道路被封锁了,所以Alice 下一步只能前往第 Li~Ri 个舞台中的一个。并且当一个节目结束的时候,Alice 只能去看另外一个节目,或者结束自己的闲逛。
具体而言就是说,假设 Alice 可以从第 i 个节目走去第 j 个节目,那么当且仅当 i<ji<ji<j 且 Li≤Aj≤Ri 。
但事实上是,Tom 非常讨厌被自己的粉丝跟踪。所以他想在只封锁掉一个节目的情况下,使得 Alice 不能到达自己所在的地方。并且为了防止意外,他还想知道有多少个这样的节目。
简而言之,Tom 想知道对于任意一个节目 p∈[1,N] ,有多少个节目 t ,使得删掉 t 之后,不存在一条从 节目1 出发到 节目p 的路径。注意,节目1 和 节目p 也是可以被删的。由于他非常的忙碌,所以他把这个任务交给了你。
输入格式
第一行包括一个正整数 N ,表示总共有 N 个节目。
第二行包括 N 个正整数 Ai ,表示第 i 个节目占用了第 Ai 个舞台。
接下来的 N 行,第 i 行包括两个正整数 Li,Ri,表示第 i 个节目的路径限制。
输出格式
总共 N 行。第 i 行包括一个整数 c ,表示当 Tom 站在第 i 个节目的时候,有多少个满足要求的节点。
特别的,若一开始就不存在从 1 出发到 i 的路径的话,你需要输出 -1 。
样例数据 1
输入
10
1 6 1 8 7 2 3 9 10 10
5 8
2 4
1 2
9 10
8 9
9 9
10 10
2 2
2 4
9 9
输出
1
2
-1
2
2
3
3
2
2
2
备注
【样例解释】
我们假如将一个节目视为一个节点的话,按题意所述,我们可以构造出一副有向图。
设对于点i,他可选的删除集合为 Si,那么很直观的就可以看出来:
对于1号节点,S1 = {1}
对于2号节点,S2 = {1,2}
对于3号节点,由于本来就不存在 1 到 3 的路径,所以应输出 -1
对于4号节点,S4 = {1,4}
对于5号节点,S5 = {1,5}
对于6号节点,S6 = {1,2,6}
对于7号节点,S7 = {1,2,7}
对于8号节点,S8 = {1,8},5 号点和 6 号点都不是合法的点。
对于9号节点,S9 = {1,9}
对于10号节点,S10 = {1,10}
【数据范围】
对于 15% 的数据,N≤100
对于 30% 的数据,N≤800
对于 50% 的数据,N≤5000
对于 70% 的数据,N≤10000
对于 100% 的数据,N≤50000
首先这题我们要用到一个叫做支配树(dominatordominatordominator treetreetree)的东西,还有一个叫做主席树的东西。如果不会的请自行百度,如果只想了解支配树在DAG上的姿势请戳这里
那么在学习了dominatordominatordominator treetreetree 过后,我们继续解决这道题吧。
我们从000分算法开始分析
000分算法:
随便写一个瞎暴力(略)
151515分算法:
我们显然可以O(n2)O(n^2)O(n2)建图,枚举终点和断点i,ji,ji,j,再暴力判断断掉jjj后是否存在1−>i1->i1−>i的路径
303030分算法:
将151515分算法进行优化,构图仍然可以O(n2)O(n^2)O(n2),我们只需改改统计必经点个数的算法,怎么做呢?
我们直接枚举必经点jjj,然后直接从起点sss开始dfsdfsdfs,将没有访问到的点的答案个数加111即可。
505050分算法:
如果我们沿用前两种算法,计算答案的时间显然太长了,而且经过尝试我们不难发现不能使用tarjantarjantarjan算法来统计,这个时候我们就要用到我们刚刚补充的dominatordominatordominator treetreetree了,这样我们可以拿到505050分了
100100100分算法?
不难想到要改变建图的方式来改进时间效率:由于题目中有限制:i,ji,ji,j之间连边当且仅当i<ji<ji<j且Li≤Aj≤RiLi \le Aj\le RiLi≤Aj≤Ri,如果我们改变枚举建边的顺序,倒序从n−>1n->1n−>1建边,那么如果我们用主席树维护限制的区间[Li,Ri][Li,Ri][Li,Ri],将AiAiAi看做是“单点修改”的值进行修改。
由于我们使用了主席树来维护,所以并不会有MLEMLEMLE这种事情发生。
那么假如现在要向Ti,L,RT_i,L,RTi,L,R中加入一个jjj,那么我们需要把Pi,L,RP_i,L,RPi,L,R连接到jjj,同样的,我们还需要把Pi,L,RP_i,L,RPi,L,R连接到剩下的属于Si,L,RS_i,L,RSi,L,R的节点,又因为我们可以发现Si,L,R−Si+1,L,R=jS_i,L,R−S_i+1,L,R=jSi,L,R−Si+1,L,R=j所以我们只需要把Pi,L,RP_i,L,RPi,L,R连接到Pi+1,L,RP_{i+1},L,RPi+1,L,R,显然原DAGDAGDAG中的连通性是不会改变的
贴贴代码:
#include<bits/stdc++.h>
#define N 900005
using namespace std;
int n,first[N],fa[N][21],dep[N],ans[N],du[N],stk[N],tot=0,m,maxn;
bool vis[N];
struct edge{int v,next;}e[N*5];
inline void add(int u,int v){
e[++tot].v=v;
e[tot].next=first[u];
first[u]=tot;
}
inline int lca(int u,int v){
if(dep[u]>dep[v])swap(u,v);
for(int i=maxn;i>=0;--i)if(dep[fa[v][i]]>=dep[u])v=fa[v][i];
if(u==v)return u;
for(int i=maxn;i>=0;--i)if(fa[v][i]!=fa[u][i])v=fa[v][i],u=fa[u][i];
return fa[v][0];
}
inline void bfs(){
queue<int>q;
q.push(1);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];i;i=e[i].next){
int v=e[i].v;
++du[v];
if(vis[v])continue;
vis[v]=1,q.push(v);
}
}
}
inline void sol(){
stack<int>s;
s.push(1);
while((1<<maxn)<=m)++maxn;
while(!s.empty()){
int x=s.top();
s.pop();
dep[x]=dep[fa[x][0]]+1;
ans[x]=ans[fa[x][0]]+(x<=n);
for(int i=1;i<=maxn;++i)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=first[x];i;i=e[i].next){
int v=e[i].v;
if(!fa[v][0])fa[v][0]=x;
else fa[v][0]=lca(x,fa[v][0]);
if(!(--du[v]))s.push(v);
}
}
for(int i=1;i<=n;++i){
if(dep[i])printf("%d\n",ans[i]);
else printf("-1\n");
}
}
struct Node{int l,r;}T[N];
int rt[N],l[N],r[N],a[N],pos=0;
inline long long read(){
long long ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
return ans;
}
inline void build(int p,int u,int l,int r,int ql,int qr){
if(p==0)return;
if(qr<l||ql>r)return;
if(ql<=l&&r<=qr){add(u,p+n);return;}
int mid=l+r>>1;
build(T[p].l,u,l,mid,ql,qr);
build(T[p].r,u,mid+1,r,ql,qr);
}
inline void update(int p,int &o,int v,int l,int r,int val){
o=++pos;
T[o]=T[p];
if(p)add(o+n,p+n);
add(o+n,v);
if(l==r)return;
int mid=l+r>>1;
if(val<=mid)update(T[p].l,T[o].l,v,l,mid,val);
else update(T[p].r,T[o].r,v,mid+1,r,val);
}
int main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n;++i)l[i]=read(),r[i]=read();
for(int i=n;i;--i){
build(rt[i+1],i,1,n,l[i],r[i]);
update(rt[i+1],rt[i],i,1,n,a[i]);
}
m=n+pos;
bfs();
sol();
return 0;
}
2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)的更多相关文章
- 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...
- [BZOJ 4771]七彩树(可持久化线段树+树上差分)
[BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...
- 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665
如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...
- 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...
- BZOJ.4771.七彩树(可持久化线段树)
BZOJ 考虑没有深度限制,对整棵子树询问怎么做. 对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(- ...
- BZOJ4771七彩树——可持久化线段树+set+树链的并+LCA
给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义dept ...
- BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3483 [题目大意] 给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模 ...
- BZOJ 3439 Kpm的MCpassword Trie树+可持久化线段树
题目大意:给定n个字符串,对于每一个字符串求以这个字符串为后缀的字符串中第k小的编号 首先将字符串反转 那么就变成了对于每一个字符串求以这个字符串为前缀的字符串中第k小的编号 然后考虑对字符串排序 那 ...
- [TS-A1505] [清橙2013中国国家集训队第二次作业] 树 [可持久化线段树,求树上路径第k大]
按Dfs序逐个插入点,建立可持久化线段树,每次查询即可,具体详见代码. 不知道为什么,代码慢的要死,, #include <iostream> #include <algorithm ...
随机推荐
- Codeforces Round #520 (Div. 2)
Codeforces Round #520 (Div. 2) https://codeforces.com/contest/1062 A #include<bits/stdc++.h> u ...
- UmBasketella
UmBasketella http://poj.org/problem?id=3737 Time Limit: 1000MS Memory Limit: 65536K Total Submissi ...
- 多线程通信(wait和notify)
线程通信概念: 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一.当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时 ...
- c#: UrlDecode()
1.源起: KV需要解析从插件传来的URL网址,因为其可能经过编码,所以需要解码. 初用System.Web.HttpUtility.UrlDecode()这个函数,但根据用户环境crash场景,发现 ...
- mysql 中 replace into 与 insert into on duplicate key update 的使用和不同点
replace into和insert into on duplicate key update都是为了解决我们平时的一个问题 就是如果数据库中存在了该条记录,就更新记录中的数据,没有,则添加记录. ...
- 地图调起URI API(通过连接直接调用百度地图)
网站:http://lbsyun.baidu.com/index.php?title=uri/api/web 地图调起URI API 百度地图URI API是为开发者提供直接调起百度地图产品(百度We ...
- JQuery.validate 错误信息对话框
<script src="${pageContext.request.contextPath}/static/js/jquery-1.12.1.js"type="t ...
- C++树的插入和遍历(关于指针的指针,指针的引用的思考)
题目 写一个树的插入和遍历的算法,插入时按照单词的字典顺序排序(左边放比它"小"的单词,右边放比它"大"的单词),对重复插入的单词进行计数. 程序源码 #inc ...
- nodejs 开发服务端 child_process 调试方法(1)
由于最近正在做一个服务端项目,采用了nodejs引擎开发,主要是master-worker工作机制;主进程可以直接调试,但是子进程调试好像有点麻烦,我没有找到好的方法; worker这里,我分拆成了几 ...
- MCS-51与8086指令系统比较