HDU 4638 树状数组 想法题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638
解题思路:
题意为询问一段区间里的数能组成多少段连续的数。先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么添加完i个数后的答案是多少?可以看出,是根据a[i]-1和a[i]+1是否已经添加而定的,如果a[i]-1或者a[i]+1已经添加一个,则段数不变,如果都没添加则段数加1,如果都添加了则段数减1。设v[i]为加入第i个数后的改变量,那么加到第x数时的段数就是sum{v[i]} (1<=i<=x}。仔细想想,若删除某个数,那么这个数两端的数的改变量也会跟着改变,这样一段区间的数构成的段数就还是他们的v值的和。将询问离线处理,按左端点排序后扫描一遍,左边删除,右边插入,查询就是求区间和。
以上摘自杭电的解题报告
标程:标程是从左边插入,从右边删除
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N = ;
struct Q
{
int l,r,id;
}query[N];
bool cmp(Q x,Q y)
{
return x.r>y.r;
}
int a[N],c[N],d[N];
int lowbit(int x)
{
return x&(-x);
}
void up(int x,int v)
{
while(x<N)
{
c[x]+=v;
x+=lowbit(x);
}
}
int getsum(int x)
{
int r=;
while(x>)
{
r+=c[x];
x-=lowbit(x);
}
return r;
}
bool u[N];
int ret[N],ps[N];
int main()
{
int T,n,m,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d",&a[i]);
ps[a[i]]=i;
}
memset(c,,sizeof(c));
memset(d,,sizeof(d));
memset(u,,sizeof(u));
for(i=n;i>;i--)
{
if(u[a[i]-])d[i]++;
if(u[a[i]+])d[i]++;
if(d[i]==)
{
up(i,);
}
else if(d[i]==)
{
up(i,-);
}
u[a[i]]=true;
}
for(i=;i<m;i++)
{
scanf("%d%d",&query[i].l,&query[i].r);
query[i].id=i;
}
sort(query,query+m,cmp);
int j=n;
for(i=;i<m;i++)
{
while(j>query[i].r)
{
if(a[j]>&&ps[a[j]-]<j)
{
d[ps[a[j]-]]--;
up(ps[a[j]-],);
}
if(a[j]<n&&ps[a[j]+]<j)
{
d[ps[a[j]+]]--;
up(ps[a[j]+],);
}
j--;
}
ret[query[i].id]=getsum(query[i].r)-getsum(query[i].l-);
}
for(i=;i<m;i++)printf("%d\n",ret[i]);
}
return ;
}
我觉得看完解题思路后我还是不太明白,就模拟了一下样例。
3 1 2 5 4
得到的数组v 为 1 1 -1 1 0
这时查询任意1-k区间的段数=sum(vi)(1=<i<=k),都是对的···神奇···
在删除3后,3-1所在的位置为3,即v[3]=v[3]+1,3+1所在的位置为5。++v[5]。
v数组变为 1 1 0 1 0 ,查询2-i区间的段数=sum(vi)(2=<i<=k),同样是对的···更神奇···有兴趣的可以自己证明
我的代码:
#include <cstdio>
#include <algorithm>
#define N 100005
using namespace std;
struct Node
{
int l,r,index;
} p[N];
int a[N],rank[N],ans[N],c[N];
int n,m; bool cmp(Node a,Node b)
{
return a.l < b.l;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int v)
{
while(x<N)
{
c[x] += v;
x += lowbit(x);
}
}
int sum(int x)
{
int s =;
while(x)
{
s += c[x];
x -= lowbit(x);
}
return s;
} void init()
{
scanf("%d%d",&n,&m);
rank[] =rank[n+] = n+;
for(int i=; i<=n; ++i)
{
scanf("%d",&a[i]);
rank[a[i]] = i;
}
for(int i=; i<m; ++i)
{
scanf("%d%d",&p[i].l,&p[i].r);
p[i].index = i;
}
}
int main()
{
// freopen("in.cpp","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
init();
memset(c, , sizeof(c) );
for(int i=; i<=n; ++i)
{
int d =;
if(rank[a[i]+] < i ) ++d;
if(rank[a[i]-] < i ) ++d;
if(d == )
add(i,);
else if(d == )
add(i,-);
}
sort(p,p+m,cmp);
rank[] = rank[n+] = ;
int j=;
for(int i=; i<m; ++i)
{
int t = p[i].l;
while(j < t)
{
if(rank[a[j]+] > j)
add(rank[a[j]+],);
if(rank[a[j]-] > j)
add(rank[a[j]-],);
++j;
}
ans[p[i].index] = sum(p[i].r)-sum(p[i].l-);
}
for(int i=; i<m; ++i)
printf("%d\n",ans[i]);
}
return ;
}
HDU 4638 树状数组 想法题的更多相关文章
- hdu 4638 树状数组 区间内连续区间的个数(尽可能长)
Group Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- hdu 4638 树状数组
思路:将查询区间按右节点的升序排列,然后插入第i个数的时候,若nun[i]+1已经插入,那么就update(pre[num[i]+1],-1):pre[]表示的是该数的位置.同样若 num[i]-1存 ...
- hdu 1166 树状数组模板题
#include<stdio.h> #include<string.h> #define N 51000 int c[N],n; int number(int x) { r ...
- HDU 1166 敌兵布阵(线段树/树状数组模板题)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- st表树状数组入门题单
预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...
- hdu 4777 树状数组+合数分解
Rabbit Kingdom Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- 敌兵布阵 HDU - 1166 (树状数组模板题,线段树模板题)
思路:就是树状数组的模板题,利用的就是单点更新和区间求和是树状数组的强项时间复杂度为m*log(n) 没想到自己以前把这道题当线段树的单点更新刷了. 树状数组: #include<iostrea ...
- 树状数组训练题1:弱弱的战壕(vijos1066)
题目链接:弱弱的战壕 这道题似乎是vijos上能找到的最简单的树状数组题了. 原来,我有一个错误的思想,我的设计是维护两个树状数组,一个是横坐标,一个是纵坐标,然后读入每个点的坐标,扔进对应的树状数组 ...
- bzoj1103树状数组水题
(卧槽,居然规定了修改的两点直接相连,亏我想半天) 非常水的题,用dfs序(而且不用重复,应该是直接规模为n的dfs序)+树状数组可以轻松水 收获:树状数组一遍A(没啥好骄傲的,那么简单的东西) #i ...
随机推荐
- JavaScript权威指南--脚本化CSS
知识要点 客户端javascript程序员对CSS感兴趣的是因为样式可以通过脚本编程.脚本化css启用了一系列有趣的视觉效果.例如:可以创建动画让文档从右侧“滑入”.创造这些效果的javascript ...
- Codeforces 595C - Warrior and Archer
595C - Warrior and Archer 思路:设最后答案的区间为[l,r],那么r-l等于n/2,因为在(l,r)中的点都是其中一个人挖掉的,[0,l)和(r,n]中的点是另一个人挖掉的, ...
- External RNA Controls Consortium (ERCC)
ERCC是啥? 外部RNA控制联盟,就是一套RNA-seq,基因表达检测过程中的控制系统,使得结果具有可重复性. RNA Spike-in Controls for Gene Expression W ...
- Silverlight自定义控件系列 – TreeView (2) 基本布局和States
TreeView的树形结构都以缩进方式显示,现在来完成这部分. 首先,要定义出每个节点上都包含什么东西.先看看Win7资源管理器的TreeView: 图2.1 资源管理器 一个通用的TreeView至 ...
- LeetCode--111--最长公共前缀
问题描述: 给定一个二叉树,找出其最小深度. 最小深度是从根节点到最近叶子节点的最短路径上的节点数量. 说明: 叶子节点是指没有子节点的节点. 示例: 给定二叉树 [3,9,20,null,null, ...
- memcached set命令的大致处理逻辑笔记
这次记录状态机的主要逻辑,跟踪set命令的执行流程,暂不涉及到内存申请这一块,下面内容基本都是代码注释 首先还是补充了解下客户连接在发送数据到数据被处理并返回过程中conn的各种状态的表示 enum ...
- 51 jquery 节点操作和 bootstrapt
jquery 和 bootstrapt1.jquery each 函数 1.each 循环方式一: 可循环对象: var arr =["alex","deng" ...
- 决策树ID3算法实现
决策树的ID3算法基于信息增益来选择最优特征,于是自己实现了一把,直接上代码. """ CreateTime : 2019/3/3 22:19 Author : X Fi ...
- shell里的/dev/null 2>&1详解
shell中可能经常能看到: >/dev/null 2>&1 命令意思是:标准输出stdout 和标准错误输出stderr 也重定向到空设备文件,即不显示输出信息 分解这个组合:“ ...
- linux分析、诊断及调优的必备“杀器”之一
下面分别列出linux分析.诊断及调优时用到的工具,并分别进行说明,以方便自己和其他同学参考学习,禁止转载. 1.top top - 02:06:59 up 4 days, 17:14, 2 user ...