P2182【河北OI 2012 DAY1】采花

问题描述

萧芸斓是Z 国的公主,平时的一大爱好是采花。
今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花。花园足够大,容纳
了n 朵花,花有c 种颜色(用整数1-c 表示),且花是排成一排的,以便于公主采花。
公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,
她不允许最后自己采到的花中,某一颜色的花只有一朵。为此,公主每采一朵花,要么此前
已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花。
由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆福涵洁安排行程。福
涵洁综合各种因素拟定了m 个行程,然后一一向你询问公主能采到多少朵花(她知道你是编
程高手,定能快速给出答案!),最后会选择令公主最高兴的行程(为了拿到更多奖金!)。

输入格式

第一行四个空格隔开的整数n、c 以及m。
接下来一行n 个空格隔开的整数,每个数在[1, c]间,第i 个数表示第i 朵花的颜色。
接下来m 行每行两个空格隔开的整数l 和r(l ≤ r),表示女仆安排的行程为公主经
过第l 到第r 朵花进行采花。

输出格式

共m 行,每行一个整数,第i 个数表示公主在女仆的第i 个行程中能采到的花的颜色数。

样例输入

5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5

样例输出

2
0
0
1
0

数据范围

对于20%的数据,n ≤ 10^2,c ≤ 10^2,m ≤ 10^2;
对于50%的数据,n ≤ 10^5,c ≤ 10^2,m ≤ 10^5;
对于100%的数据,1 ≤ n ≤10^5,c ≤ n,m ≤ 10^5。


主要是两种思路,都是离线算法。
做法一:
令 C[i] C[i]表示从1到i总共出现的不同颜色且出现次数大于1的花的数量,那么预处理出每一朵花的下一个和他同颜色的花的位置,记到 next[x] next[x]数组中
令当前讨论的左端点为 x x,那么当x左移的时候,对C[i]C[i]产生的影响是 next[x] next[x]到 next[next[x]]−1 next[next[x]]-1位置的 C[i] C[i]减一,于是将区间排序,用线段树维护 C[i] C[i],进行区间操作即可。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 200005
using namespace std;
struct node{int x,y,id,ans;}B[N];
bool cmp1(node a,node b)
{return a.x<b.x;}
bool cmp2(node a,node b)
{return a.id<b.id;}
int n,c,m,A[N],NE[N],LA[N],C[N],cnt[N];
int ls[N*10],rs[N*10],v[N*10],lazy[N*10],tot;
int BT(int x,int y)
{int p=++tot;if(x<y){int mid=x+y>>1;ls[p]=BT(x,mid);rs[p]=BT(mid+1,y);}else v[p]=C[x];return p;
}
void PD(int p)
{v[ls[p]]+=lazy[p];v[rs[p]]+=lazy[p];lazy[ls[p]]+=lazy[p];lazy[rs[p]]+=lazy[p];lazy[p]=0;
}
void MD(int p,int l,int r,int x,int y,int d)
{if(lazy[p])PD(p);if(x<=l&&y>=r){lazy[p]+=d;v[p]+=d;return;}int mid=l+r>>1;if(x<=mid&&y>=l)MD(ls[p],l,mid,x,y,d);if(x<=r&&y>mid)MD(rs[p],mid+1,r,x,y,d);
}
int GS(int p,int l,int r,int k)
{if(lazy[p])PD(p);if(l==r)return v[p];int mid=l+r>>1;if(k<=mid)return GS(ls[p],l,mid,k);return GS(rs[p],mid+1,r,k);
}
int main()
{int i,j,k;scanf("%d%d%d",&n,&c,&m);for(i=1;i<=n;i++)scanf("%d",&A[i]);for(i=n;i>=1;i--){if(!LA[A[i]])NE[i]=n+1;else NE[i]=LA[A[i]];LA[A[i]]=i;}NE[n+1]=n+1;for(i=1;i<=n;i++){cnt[A[i]]++;C[i]=C[i-1];if(cnt[A[i]]==2)C[i]++;}BT(1,n);for(i=1;i<=m;i++)scanf("%d%d",&B[i].x,&B[i].y),B[i].id=i;sort(B+1,B+m+1,cmp1);i=1;j=1;while(j<=m){while(B[j].x>i)MD(1,1,n,NE[i],NE[NE[i]]-1,-1),i++;while(B[j].x==i)B[j].ans=GS(1,1,n,B[j].y),j++;}sort(B+1,B+m+1,cmp2);for(i=1;i<=m;i++)printf("%d\n",B[i].ans);
}

做法二:
始终将从当前讨论位置往后,每种颜色的第二次出现的位置的地方为1,其他地方为0,那么维护前缀和数组即可求出答案。
因此,同样用 next next数组,然后用树状数组维护前缀和。当讨论到一个询问的左端点时,右端点的前缀和值就是答案,只需要始终维护从当前讨论位置开始,每种颜色第二次出现的位置即可。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 200005
using namespace std;
struct node{int x,y,id,ans;}B[N];
bool cmp1(node a,node b)
{return a.x<b.x;}
bool cmp2(node a,node b)
{return a.id<b.id;}
int n,c,m,A[N],NE[N],LA[N],C[N],D[N];
void MD(int x,int d)
{for(int i=x;i<=n;i+=(i&-i))D[i]+=d;}
int GS(int x)
{int i,sum=0;for(i=x;i;i-=(i&-i))sum+=D[i];return sum;
}
int main()
{int i,j,k;scanf("%d%d%d",&n,&c,&m);for(i=1;i<=n;i++)scanf("%d",&A[i]);NE[n+1]=n+1;for(i=n;i>=1;i--){if(!LA[A[i]])NE[i]=n+1;else NE[i]=LA[A[i]];LA[A[i]]=i;MD(NE[i],1);MD(NE[NE[i]],-1);}for(i=1;i<=m;i++)scanf("%d%d",&B[i].x,&B[i].y),B[i].id=i;sort(B+1,B+m+1,cmp1);i=1;k=1;while(k<=m){while(i<B[k].x)MD(NE[i],-1),MD(NE[NE[i]],1),i++;while(i==B[k].x)B[k].ans=GS(B[k].y),k++;}sort(B+1,B+m+1,cmp2);for(i=1;i<=m;i++)printf("%d\n",B[i].ans);
}

NKOJ 2182 (HEOI 2012) 采花(树状数组/线段树)相关推荐

  1. D-query SPOJ - DQUERY(求区间不同数的个数)(树状数组||线段树+离散)(主席树+在线)

    English Vietnamese Given a sequence of n numbers a1, a2, -, an and a number of d-queries. A d-query ...

  2. HDU 1556 前缀和 树状数组 线段树

    解法一: a[i]表示以 i作为起点,对 i-n的气球全部上色的次数  对(start,end)区间上色 ++a[start] --a[end+1]抵消掉 end+1-n的部分 问题转换为求 a的前缀 ...

  3. jzoj3854-分组【树状数组,线段树】

    正题 题目链接:https://jzoj.net/senior/#contest/show/2990/2 题目大意 一个小队满足要求 队长的地位最高 所有队员和队长的年龄差不超过kkk 给出nnn个人 ...

  4. 模板三连击:树状数组+线段树+主席树

    没事儿干,复习模板...... 1.树状数组 本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数. 洛谷 P3374 [模板]树状数组 1 1 #include<cstdio> ...

  5. 51nod 1680区间求和 (dp+树状数组/线段树)

    不妨考虑已知一个区间[l,r]的k=1.k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间) 那么如果加入一个新的数字a[i](i = r+1) 则新区间[l, i]的答案为 ...

  6. CCF201709-5 除法(100分)【树状数组+线段树】

    试题编号: 201709-5 试题名称: 除法 时间限制: 10.0s 内存限制: 256.0MB 问题描述: 问题描述 小葱喜欢除法,所以他给了你N个数a1, a2, ⋯, aN,并且希望你执行M次 ...

  7. POJ2182 HDU2711 Lost Cows【树状数组+线段树】

    Lost Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17113 Accepted: 10664 Descripti ...

  8. P2357 守墓人(树状数组/线段树)

    题目描述 在一个荒凉的墓地上 有一个令人尊敬的守墓人, 他看守的墓地从来 没有被盗过, 所以人们很放心的把自己的先人的墓 安顿在他那 守墓人能看好这片墓地是必然而不是偶然..... 因为....守墓人 ...

  9. 差分+树状数组 线段树【P2357】 守墓人

    题目描述-->p2357 守墓人 敲了一遍线段树,水过. 树状数组分析 主要思路: 差分 简单介绍一下差分(详细概念太麻烦,看下面. 给定一个数组 7 8 6 5 1 8 18 20 35 // ...

最新文章

  1. 史上最完整的人工智能书单大全,学习AI的请收藏好
  2. python底层代码里面的参数_梯度下降算法讲解及python底层实现
  3. 已知/未知宽高的浮动元素水平居中对齐 和 图片水平垂直居中对齐
  4. JavaScript将成为浏览器战争的主战场
  5. spring配置详解-属性注入(set方式)
  6. 100层楼2个鸡蛋,如何得知鸡蛋能承受几层的撞击
  7. 初学者Web介绍一些前端开发中的基本概念用到的技术
  8. 2020年阿里云年中大促【福利】【选品】全攻略
  9. 软件编程,在于设计和思想
  10. 机器学习十大常用算法
  11. 小程序发布上线流程_微信小程序发布流程
  12. 冰点还原精灵怎么使用
  13. java 打印星号_JAVA打印星号
  14. 计算机打印机能不能取消正在,删除HP打印机驱动程序. 打印机驱动程序正在使用中,无法删除...
  15. 高管激励的有效手段----股权激励
  16. PTA L2-043龙龙送外卖
  17. 多目标优化算法(四)NSGA3(NSGAIII)论文复现以及matlab和python的代码
  18. JS如何判断是否为ie浏览器的方法(包括IE10、IE11在内)
  19. Redis源码剖析和注释(十六)---- Redis输入输出的抽象(rio)
  20. (纯故事)我简单写几篇,就这一次

热门文章

  1. 为什么不建议直接使用 @Async 注解
  2. 神经网络除了bp还有什么,BP神经网络能够做什么
  3. VSTO2005架构概述
  4. JAVA面向对象继承之父类宝典(二)
  5. MikTex+Texmaker环境LaTeX使用bib文件引用参考文献步骤
  6. 前端技术栈之html,css,js
  7. WIKO+鸿蒙生态:海外品牌中国化的新范式
  8. 干货|WMS仓库管理系统提高企业仓库管理效率(下)
  9. selenium java 保存网页为mhtml单个文件
  10. App开发中如何实现灰度发布?