题解 P3605 [USACO17JAN]Promotion Counting P
分块\(yyds\)
————关于线段树合并的题我用分块过掉这件事
先说正解
正解当然是线段树合并等一类做法了
至于解析。。。出门右转题解区第一篇 (就是他让我看不懂,然后用分块打的\(QAQ\))
给出 fengwu 的\(code\)
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
#define re register int
const int N=100005;
int n;
int p[N],d[N];
int to[N],nxt[N],head[N],rp;
int rt[N],ans[N];
bool cmp(int x,int y){return p[x]<p[y];}
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
struct node{
int sum[N*80];
int ls[N*80],rs[N*80];
int cnt;
int insert(int x,int l,int r,int pos){
if(!x)x=++cnt;
sum[x]++;
if(l==r)return x;
int mid=(l+r)>>1;
if(pos<=mid)ls[x]=insert(ls[x],l,mid,pos);
else rs[x]=insert(rs[x],mid+1,r,pos);
sum[x]=sum[ls[x]]+sum[rs[x]];
return x;
}
int query(int x,int l,int r,int pos){
if(!x)return 0;
if(l==r)return sum[x];
int mid=(l+r)>>1;
if(pos<=mid)return query(ls[x],l,mid,pos)+sum[rs[x]];
else return query(rs[x],mid+1,r,pos);
}
int marge(int x,int y,int l,int r){
if(!x)return y+x;
if(!y)return x+y;
if(l==r){
sum[x]+=sum[y];
return x;
}
int mid=(l+r)>>1;
ls[x]=marge(ls[x],ls[y],l,mid);
rs[x]=marge(rs[x],rs[y],mid+1,r);
sum[x]=sum[ls[x]]+sum[rs[x]];
return x;
}
}xds;
void dfs(int x){
for(re i=head[x];i;i=nxt[i])
dfs(to[i]);
rt[x]=xds.insert(rt[x],1,n+1,p[x]);
for(re i=head[x];i;i=nxt[i])
rt[x]=xds.marge(rt[x],rt[to[i]],1,n+1);
ans[x]=xds.query(rt[x],1,n+1,p[x]+1);
}
int main(){
scanf("%d",&n);
for(re i=1;i<=n;i++)
scanf("%d",&p[i]),d[i]=i;
sort(d+1,d+n+1,cmp);
for(re i=1;i<=n;i++)p[d[i]]=i;
for(re i=2;i<=n;i++){
int f;
scanf("%d",&f);
add_edg(f,i);
}
dfs(1);
for(re i=1;i<=n;i++){
printf("%d\n",ans[i]);
}
}
再谈分块
分块么,无非就是优化的暴力,所以调试到崩溃的我斗胆交了一下暴力代码=>\(70pts\)
出乎意料!!!
然后我吸了口毒氧 ,再然后就\(100pts\)了。。。
这个不会的就不用出门了,凑合看看就能懂,下面给出\(code\)以及我的\(link\)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int m,n,tot,cnt,tmp,tim,ans,fz[N+5],Ans[N+5],tail[N+5],ys[N+5],num[N+5],nxt[N+5],head[N+5],ver[N+5];
struct jz
{
int id,num,pos;
}s[N+5];
bool comp(jz x,jz y)
{
if(x.id!=y.id)
return x.id<y.id;
}
void lsh()
{
for(int i=1;i<=n;i++)
ys[i]=s[i].num;
sort(ys+1,ys+n+1);
tmp=unique(ys+1,ys+n+1)-ys-1;
for(int i=1;i<=n;i++)
s[i].num=lower_bound(ys+1,ys+tmp+1,s[i].num)-ys;
}
void add_edge(int x,int y)
{
ver[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;
}
int dfs(int x)
{
s[x].id=++tim;
if(head[x]==0)
return tail[x]=x;
for(int i=head[x];i;i=nxt[i])
{
int jud=dfs(ver[i]);
if(s[jud].id>s[tail[x]].id)
tail[x]=jud;
}
return tail[x];
}
int ask(int li,int ri,int k)
{
if(li>ri) return 0;
for(int i=li;i<=ri;i++)
if(s[i].num>=k)
ans++;
return ans;
}
signed main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&s[i].num),s[i].pos=i;
for(int i=2,x;i<=n;i++)
scanf("%d",&x),add_edge(x,i);
lsh();
dfs(1);
sort(s,s+n+1,comp);
for(int i=1;i<=n;i++)
fz[s[i].pos]=s[i].id;
for(int i=1;i<=n;i++)
Ans[s[i].pos]=ask(i+1,fz[tail[s[i].pos]],s[i].num+1);
for(int i=1;i<=n;i++)
printf("%d\n",Ans[i]);
return 0;
}
然后嘞就是详解以及分块做法了(调了好久就因为一个\(j\)打成了\(i\),痛哭\(.jpg\))\(link\)
思路比较简单
先是读入
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&s[i].num),s[i].pos=i;
for(int i=2,x;i<=n;i++)
scanf("%d",&x),add_edge(x,i);
然后离散化一下
void lsh()
{
for(int i=1;i<=n;i++)
ys[i]=s[i].num;
sort(ys+1,ys+n+1);
tmp=unique(ys+1,ys+n+1)-ys-1;
for(int i=1;i<=n;i++)
s[i].num=lower_bound(ys+1,ys+tmp+1,s[i].num)-ys;
}
然后就是重点了,先建边,读入的时候一定要从2开始,因为1是没有上司的然后dfs一下求出每个点被便历到的\(s[i].id\)值,同时记录一下\(tail[i]\)(表示在原顺序下的i的最后一个下属)
分为以下两种情况:
已经是最后一个,没有下属,那么\(head[x]\)一定是0,此时直接\(return\),并且给\(tail[x]\)赋值
有子节点,此时用一个\(jud\)记录一下子节点返回的\(tail\),然后与现在存的\(tail\)比较\(id\)值,取\(id\)值较大的,即最后扫描到的,最后不要忘了\(return\)一下
int dfs(int x)
{
s[x].id=++tim;
if(head[x]==0)
return tail[x]=x;
for(int i=head[x];i;i=nxt[i])
{
int jud=dfs(ver[i]);
if(s[jud].id>s[tail[x]].id)
tail[x]=jud;
}
return tail[x];
}
然后给\(s\)结构体按照\(id\)顺序排个序,顺便用\(fz\)数组记录一下:\(fz[i]=j\)表示先前为第\(i\)的点现在的下标是\(j\)
接下来就是愉快的分块了
t=sqrt(n);
for(int i=1;i<=t;i++)
{
l[i]=(i-1)*sqrt(n)+1;
r[i]=i*sqrt(n);
}
if(r[t]<n)
{
t++;
l[t]=r[t-1]+1;
r[t]=n;
}
接下来的做法就与教主的魔法相似了,大概意思就是再建一个数组储存每个块排序后的样子,在二分查找一下就好了,不会的嘛,老办法,出门右转题解区\(qwq\)。
最后在拿一个\(Ans\)数组存一下输出就\(OK\)了
\(code\)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int m,t,n,tot,cnt,tmp,tim,ans,fz[N+5],Ans[N+5],tail[N+5],ys[N+5],pos[N+5],l[N+5],r[N+5],num[N+5],nxt[N+5],head[N+5],ver[N+5];
struct jz
{
int id,num,pos;
}s[N+5];
bool comp(jz x,jz y)
{
if(x.id!=y.id)
return x.id<y.id;
return x.num>y.num;
}
void lsh()
{
for(int i=1;i<=n;i++)
ys[i]=s[i].num;
sort(ys+1,ys+n+1);
tmp=unique(ys+1,ys+n+1)-ys-1;
for(int i=1;i<=n;i++)
s[i].num=lower_bound(ys+1,ys+tmp+1,s[i].num)-ys;
}
void add_edge(int x,int y)
{
ver[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;
}
int dfs(int x)
{
s[x].id=++tim;
if(head[x]==0)
return tail[x]=x;
for(int i=head[x];i;i=nxt[i])
{
int jud=dfs(ver[i]);
if(s[jud].id>s[tail[x]].id)
tail[x]=jud;
}
return tail[x];
}
int ask(int li,int ri,int k)
{
if(li>ri) return 0;
int p=pos[li],q=pos[ri],ans=0;
if(p==q)
{
for(int i=li;i<=ri;i++)
if(s[i].num>=k)
ans++;
return ans;
}
for(int i=li;i<=r[p];i++)
if(s[i].num>=k)
ans++;
for(int i=p+1;i<q;i++)
ans+=r[i]+1-(lower_bound(num+l[i],num+r[i]+1,k)-num);
for(int i=l[q];i<=ri;i++)
if(s[i].num>=k)
ans++;
return ans;
}
signed main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&s[i].num),s[i].pos=i;
for(int i=2,x;i<=n;i++)
scanf("%d",&x),add_edge(x,i);
lsh();
dfs(1);
sort(s,s+n+1,comp);
for(int i=1;i<=n;i++)
fz[s[i].pos]=s[i].id;
t=sqrt(n);
for(int i=1;i<=t;i++)
{
l[i]=(i-1)*sqrt(n)+1;
r[i]=i*sqrt(n);
}
if(r[t]<n)
{
t++;
l[t]=r[t-1]+1;
r[t]=n;
}
for(int i=1;i<=t;i++)
{
for(int j=l[i];j<=r[i];j++)
{
pos[j]=i;
num[j]=s[j].num;
}
sort(num+l[i],num+r[i]+1);
}
for(int i=1;i<=n;i++)
Ans[s[i].pos]=ask(i+1,fz[tail[s[i].pos]],s[i].num+1);
for(int i=1;i<=n;i++)
printf("%d\n",Ans[i]);
return 0;
}
不得不说这个题让我的调试能力大增。。。
题解 P3605 [USACO17JAN]Promotion Counting P的更多相关文章
- 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...
- 树状数组 P3605 [USACO17JAN]Promotion Counting晋升者计数
P3605 [USACO17JAN]Promotion Counting晋升者计数 题目描述 奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训--牛是可怕的管理者! 为了方便,把奶牛从 ...
- 洛谷P3605 [USACO17JAN] Promotion Counting 晋升者计数 [线段树合并]
题目传送门 Promotion Counting 题目描述 The cows have once again tried to form a startup company, failing to r ...
- luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题目链接 luogu 思路 可以说是线段树合并的练手题目吧 也没啥说的,就是dfs,然后合并... 看代码吧 错误 和写主席树错的差不多 都是变量写错.... 代码 #include <bits ...
- P3605 [USACO17JAN]Promotion Counting晋升者计数
思路 线段树合并的板子.. 和子节点合并之后在值域线段树上查询即可 代码 #include <cstdio> #include <algorithm> #include < ...
- 洛谷 P3605 [USACO17JAN]Promotion Counting晋升者计数
题目描述 The cows have once again tried to form a startup company, failing to remember from past experie ...
- Luogu3605 [USACO17JAN]Promotion Counting晋升者计数
Luogu3605 [USACO17JAN]Promotion Counting晋升者计数 给一棵 \(n\) 个点的树,点 \(i\) 有一个权值 \(a_i\) .对于每个 \(i\) ,求 \( ...
- 题解 P3605 【[USACO17JAN]Promotion Counting晋升者计数】
这道题开10倍左右一直MLE+RE,然后尝试着开了20倍就A了...窒息 对于这道题目,我们考虑使用线段树合并来做. 所谓线段树合并,就是把结构相同的线段树上的节点的信息合在一起,合并的方式比较类似左 ...
- [USACO17JAN]Promotion Counting 题解
前言 巨佬说:要有线段树,结果蒟蒻打了一棵树状数组... 想想啊,奶牛都开公司当老板了,我还在这里码代码,太失败了. 话说奶牛开个公司老板不应该是FarmerJohn吗? 题解 刚看到这道题的时候竟然 ...
随机推荐
- linux命令解压压缩rar文件
一.widonds下打包rar文件并上传 yum install lrzsz rz test.rar 二.下载并安装rar软件 2.1 下载 mkdir -p /home/oldboy/tools c ...
- 全套Project版本安装教程及下载地址
1:Project 2007 安装教程及下载地址 https://mp.weixin.qq.com/s/8iI7x1qjon0yAdo3bStjzw 2:Project 2010 安装教程及下载地址 ...
- Spring MVC工作原理及源码解析(四) ViewResolver实现原理及源码解析
0.ViewResolver原理介绍 根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,View 是用来渲染页面的,也就是将 Mode ...
- (四)Jira Api对接:缺陷分析和任务分析
迭代进行期间或者结束后,在我们的测试日报或者测试报告中需要体现缺陷详细情况,甚至大家工作效率情况.本文就讨论下如何通过jira api获取缺陷信息并进行分析,同时获取需求子任务情况来了解测试和开发的工 ...
- 数据库和SQL概述
一.数据库的概念 1.DB 数据库(database):存储数据的"仓库".它保存了一系列有组织的数据. 2.DBMS 数据库管理系统(Database Management Sy ...
- IPC机制key值的各位组成
key_t ftok(const char *_pathname, int _proj_id) key值的第31~24位为ftok()第二个参数的低8位: key值的第23~16位为ftok()第一个 ...
- [BUAA2021软工助教]结对项目-第二阶段小结
一.作业链接 结对项目-第二阶段 二.优秀作业推荐 本次博客作业虽然是简单总结,但是以下作业中都不乏有思考.有亮点的精彩内容,推荐给同学们阅读学习. 磨练,结对编程!(中) zzx 和 zzy 同学实 ...
- 服务治理演进剖析 & Service Mesh、 xDS核心原理梳理
基于XDS协议实现控制面板与数据面板通信分享 基于这段时间在同程艺龙基础架构部的蹲坑,聊一聊微服务治理的核心难点.历史演进.最新动态, 以上内容属自我思考,不代表同程艺龙技术水准.如理解有偏差.理解不 ...
- JAVA并发(2)-ReentrantLock的见解
上节,我们讲了AQS的阻塞与释放实现原理,线程间通信(Condition)的原理.这次,我们就讲讲基于AQS实现的ReentrantLock(重入锁). 1. 介绍 结合上面的ReentrantLoc ...
- [bug] CM / CDH 主机运行状态不良情况
参考 https://blog.csdn.net/fhfkv8644/article/details/82383196 无法发出查询:Host Monitor 未运行 https://blog.csd ...