【HZOI】 赏花
2013-10-04 19:18
148 查看
Description
衡水湖为了迎接国际马拉松比赛,在跑道旁种了一排花,每朵花都有一种颜色色,共有N 朵。
现在 sky 和 leaf 到衡水湖赏花,leaf 总会问 sky 一些问题,比如第l朵花到第r朵花之间能看到多少种颜色的花?
sky 算得木有那么快,于是请你来帮帮他。
Input
第一行一个数N
接下来一行N 个数Ci,表示花的颜色
接下来一行一个数M
接下来M行,每行两个数l,r,表示 leaf 的一个问题,询问l到r之间有多少种颜色的花。
Output
M行,每行表示 leaf 一个问题的答案
Sample Input
Sample Output
Hint
N≤100000,M≤200000,1≤Ci≤100000
【分析】
看完题目,第一反应是尽管提问次数很多,但没有修改操作。于是便可以离线处理了。离线处理也就意味着预处理,那空间换时间。那么怎么换呢?可以用树状数组来维护一个前缀和。具体步骤如下:
1.给提问按照左区间端点为第一关键字,右区间端点为第二关键字(右区间排序可有可无),均从小到大排序。
2.从后往前将所有相同的颜色拉成一个链表(像存边一样,一个last数组和一个next数组)。然后将所有的last即每个颜色从左边第一次出现的位置置为1(同时树状数组也修改)。
3.查询区间时,将当前区间左端点左边的所有的1全部移至相应的next位置。原位置改为0,next位置改为1。那么这段区间的答案便是get(y)-get(x-1)。get表示利用树状数组求前缀和。
再看看这种做法,其实质也就相当于先让每种颜色只出现在最左边的位置。然后随着区间的移动(排序后的),颜色依次出现在下一个位置。然后原位置标记为空,来保证一种颜色不会重复计算。而树状数组只不过是维护动态的前缀和罢了。
(PS:注意输出答案的时候,把顺序调整回来)
【代码】
衡水湖为了迎接国际马拉松比赛,在跑道旁种了一排花,每朵花都有一种颜色色,共有N 朵。
现在 sky 和 leaf 到衡水湖赏花,leaf 总会问 sky 一些问题,比如第l朵花到第r朵花之间能看到多少种颜色的花?
sky 算得木有那么快,于是请你来帮帮他。
Input
第一行一个数N
接下来一行N 个数Ci,表示花的颜色
接下来一行一个数M
接下来M行,每行两个数l,r,表示 leaf 的一个问题,询问l到r之间有多少种颜色的花。
Output
M行,每行表示 leaf 一个问题的答案
Sample Input
6 1 2 3 4 3 5 3 1 2 3 5 2 6
Sample Output
2 2 4
Hint
N≤100000,M≤200000,1≤Ci≤100000
【分析】
看完题目,第一反应是尽管提问次数很多,但没有修改操作。于是便可以离线处理了。离线处理也就意味着预处理,那空间换时间。那么怎么换呢?可以用树状数组来维护一个前缀和。具体步骤如下:
1.给提问按照左区间端点为第一关键字,右区间端点为第二关键字(右区间排序可有可无),均从小到大排序。
2.从后往前将所有相同的颜色拉成一个链表(像存边一样,一个last数组和一个next数组)。然后将所有的last即每个颜色从左边第一次出现的位置置为1(同时树状数组也修改)。
3.查询区间时,将当前区间左端点左边的所有的1全部移至相应的next位置。原位置改为0,next位置改为1。那么这段区间的答案便是get(y)-get(x-1)。get表示利用树状数组求前缀和。
再看看这种做法,其实质也就相当于先让每种颜色只出现在最左边的位置。然后随着区间的移动(排序后的),颜色依次出现在下一个位置。然后原位置标记为空,来保证一种颜色不会重复计算。而树状数组只不过是维护动态的前缀和罢了。
(PS:注意输出答案的时候,把顺序调整回来)
【代码】
#include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<cmath> #include<iostream> #include<algorithm> #define _lowbit(x) (x&(-x)) using namespace std; int N,M,v[100005],qx[200005],qy[200005],rank[200005],ans[200005]; int c[100005],last[100005],next[100005]; int maxv=0; void _qst_rank(int l,int r) { int i=l,j=r,mr=rank[(i+j)>>1]; while(i<=j) { while(rank[i]<mr) i++; while(rank[j]>mr) j--; if(i<=j) { swap(rank[i],rank[j]); swap(ans[i],ans[j]); i++;j--; } } if(l<j) _qst_rank(l,j); if(i<r) _qst_rank(i,r); } void _qst_qxqy(int l,int r) { int i=l,j=r,mx=qx[(i+j)>>1],my=qy[(i+j)>>1]; while(i<=j) { while((qx[i]<mx)||(qx[i]==mx&&qy[i]<my)) i++; while((qx[j]>mx)||(qx[j]==mx&&qy[j]>my)) j--; if(i<=j) { swap(qx[i],qx[j]); swap(qy[i],qy[j]); swap(rank[i],rank[j]); i++;j--; } } if(l<j) _qst_qxqy(l,j); if(i<r) _qst_qxqy(i,r); } void _in(int &x) { char t=getchar(); while(t<'0'||'9'<t) t=getchar(); for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar()); } void _out(int x,int j=1) { char t[100]; if(x==0) putchar('0'); for(;x;x/=10,j++) t[j]=x%10+'0'; for(j--;j;j--) putchar(t[j]); putchar('\n'); } void _init() { _in(N); for(int i=1;i<=N;i++) { _in(v[i]); maxv=max(maxv,v[i]); } _in(M); for(int i=1;i<=M;i++) { _in(qx[i]); _in(qy[i]); rank[i]=i; } } void _solve() { for(int i=N;i;i--) //逆序建立链表 { next[i]=last[v[i]]; last[v[i]]=i; } _qst_qxqy(1,M); //将问题排序 for(int i=1;i<=maxv;i++) if(last[i]!=0) for(int j=last[i];j<=N;j+=_lowbit(j)) c[j]++; for(int i=1;i<=M;i++) { for(int k=max(1,qx[i-1]);k<qx[i];k++) { for(int j=k;j<=N;j+=_lowbit(j)) //删除之前的标记 c[j]--; if(next[k]!=0) //如果可以移动,则移至下一位置 for(int j=next[k];j<=N;j+=_lowbit(j)) c[j]++; } int temp=0; //计算答案 for(int j=qx[i]-1;j;j-=_lowbit(j)) temp-=c[j]; for(int j=qy[i];j;j-=_lowbit(j)) temp+=c[j]; ans[i]=temp; } _qst_rank(1,M); //按输入顺序排序 for(int i=1;i<=M;i++) _out(ans[i]); } int main() { _init(); _solve(); return 0; }
相关文章推荐
- 北京3月去哪玩 赏花踏青登山六大推荐
- COGS 1658. [HZOI 2014] 合并石子 解题报告
- hzoi2015(ntt+组合数学)
- COGS2287 [HZOI 2015]疯狂的机器人
- 「HZOI 2015」Math
- 花开时节,有赏花的心情.
- 数据结构(分块):[HZOI 2015]easy seq
- [COGS2287][HZOI 2015]疯狂的机器人(NTT)
- [HZOI 2016]公路修建
- 「HZOI 2016」最长公共上升子序列
- 重阳赏花
- 赏花不必出国游 植物壁纸将春天贴上墙
- COGS2531. [HZOI 2016]函数的美 打表+欧拉函数
- COGS 2479. [HZOI 2016]偏序 双重CDQ分治+树状数组
- COGS2580:[HZOI 2015]偏序 II (三层CDQ分治+树状数组)
- 「HZOI 2016」搜城探宝
- 赏花
- UESTC_酱神赏花 2015 UESTC Training for Dynamic Programming<Problem C>
- COGS 2532. [HZOI 2016]树之美 树形dp
- COGS 2199. [HZOI 2016] 活动投票