hdu 5997 rausen loves cakes [启发式合并+树状数组/线段数]【杂类+数据结构】
来源:互联网 发布:闪电分期go淘宝商铺 编辑:程序博客网 时间:2024/06/18 11:04
题目连接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5997
—————————————————————-.
rausen loves cakes
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
rausen喜欢吃蛋糕。某天,他买了nn个蛋糕,每个蛋糕都有一个颜色,用\left[1,1000000 \right][1,1000000]中的整数来表示。rausen将它们从左到右排成一行,然后准备开始吃。
在吃之前,rausen想对蛋糕进行qq个操作。
某些时刻,rausen会把所有颜色为xx的蛋糕替换成颜色为yy的蛋糕。
另一些时刻,rausen会计算一段区间\left[x,y \right][x,y]内颜色的段数,所谓一段颜色,就是指极长的只有一种颜色的区间。例如1 4 4 1 1即为3段颜色。
然而,rausen发现,他并不会统计区间内的颜色段数,无助的rausen伤心地哭了起来(误)。而你为了安慰他,决定帮他解决这个问题。
输入描述
输入包含多组数据。第一行有一个整数TT,表示测试数据的组数,对于每组数据:
第一行输入2个整数nn,qq分别表示蛋糕的数目和操作的数目。
接下来一行nn个正整数,第ii个正整数{a}_{i}a
i
表示第ii个蛋糕的颜色。
接下来qq行,每行3个整数op\left(1\leq op\leq 2 \right)op(1≤op≤2),xx,yy,描述一个操作
对于op=1op=1,表示rausen进行替换操作,将颜色为xx的蛋糕替换成颜色为yy的蛋糕,xx、yy满足\left(1\leq x,y\leq 1000000 \right)(1≤x,y≤1000000),请注意xx可能等于yy。
对于op=2op=2,表示rausen进行计数操作,此时你需要输出区间\left[x,y \right][x,y]内颜色的段数,xx、yy满足\left(1\leq x\leq y\leq n \right)(1≤x≤y≤n)
\left(1\leq T\leq 5 \right)(1≤T≤5),\left(1\leq n\leq {10}^{5} \right)(1≤n≤10
5
),\left(1\leq q\leq {10}^{5} \right)(1≤q≤10
5
)
输出描述
对于每组测试数据的每一个计数操作,单独输出一行表示答案。
输入样例
1
5 3
1 4 4 10 1
2 1 5
1 4 10
2 3 5
输出样例
4
2
—————————————————————-.
藏了好久终于补了这个,虽然还是感觉有点乱乱的。。。。
首先考虑暴力的把一种颜色替换成另一种颜色,那么这一部分就是
那么考虑将每一种颜色所在的位置记录下来,这样的话就能降到
但是考虑
用树状数组来维护拐点(
那么来统计区间内的颜色段数就是求区间内的拐点个数+左端点是不是拐点。。
维护这个就是简单的树状数组的操作了,不再赘述,其实用线段是也可以维护的,但是线段树的代码量…
代码中有详细点的注释,可以看看..
附本题代码
————————————————————。
#include <bits/stdc++.h>using namespace std;typedef long long int LL ;/***********************************************************************/const int N = 1000000 + 5; //数列的大小int ft[N]; //ft[a]=b 是a这个颜色最后一次出现的位置是bint nt[N]; //nt[a]=b 是a这个位置的颜色上一次出现过的地方是b(因为修改 所以可能是乱序的,但是最终都是连在一起的)int u[N]; //ft[],nt[] 维护的是一种颜色链之间的关系,所以我们需要一个u[]来表示在最初的位置int cnt,n,q; //略int f[N]; //f[a]=b ,颜色号为a的颜色 现在代表颜色bint g[N]; //记录这个颜色即时的个数int a[N]; //输入的数组值int sum[N]; //树状数组#define lowbit(x) (x&(-x)) //lowbit操作void update(int index,int val){ //单点更新 (+val) for(int i=index;i<=N;i+=lowbit(i)) sum[i]+=val;}int getSum(int index) { //求解1~index的和 int ans = 0; for (int i = index; i; i -= lowbit(i)) ans += sum[i]; return ans;}/**用树状数组来维护拐点(a_{i} != a_{i+1} 那么a_i就是一个拐点)那么来统计区间内的颜色段数就是求区间内的拐点个数+左端点是不是拐点。。采取启发式合并的方式来减少计算。*/int main(){ int _ = 1; while(~scanf("%d",&_)){ while(_--){ scanf("%d %d",&n,&q); memset(ft,-1,sizeof(ft)); memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(sum,0,sizeof(sum)); cnt=0;a[0]=a[n+1]=-1; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); f[a[i]]=a[i];g[a[i]]++;u[++cnt]=i;nt[cnt]=ft[a[i]];ft[a[i]]=cnt; //printf("i=%d cnt=%d u[%d]=%d nt[%d]=%2d ft[%2d]=%d \n",i,cnt-1,cnt-1,u[cnt-1],cnt-1,nt[cnt-1],a[i],ft[a[i]]); if(a[i]!=a[i-1]) update(i,1); } int op,x,y; while(q--){ scanf("%d%d%d",&op,&x,&y); if(1==op){ if(x==y||!g[f[x]]) continue; int s=x,t=y; if(g[f[x]]>g[f[y]]) swap(y,x);//将颜色少的改成颜色多的。 这就是启发式合并。。 x=f[x],y=f[y]; //printf("x=%d y=%d\n",x,y); for(int j=ft[x];j!=-1;j=nt[j]){//然后一个一个判断增减。。。。 if (a[u[j]] != a[u[j] - 1]) update(u[j], -1); if (a[u[j]] != a[u[j] + 1]) update(u[j] + 1, -1); a[u[j]] = y; if (a[u[j]] != a[u[j] - 1]) update(u[j], 1); if (a[u[j]] != a[u[j] + 1]) update(u[j] + 1, 1); if (nt[j] == -1) { nt[j] = ft[y]; ft[y] = ft[x]; break; //将两段颜色的链连接起来. } } g[y] += g[x]; g[x] = 0; f[t] = y; f[s] = 0; //这是颜色改变后的x,y的属性,(个数,代表的颜色)。 } if(2==op) printf("%d\n",getSum(y)-getSum(x-1)+(int)(a[x]==a[x-1])); } } } return 0;}
- hdu 5997 rausen loves cakes [启发式合并+树状数组/线段数]【杂类+数据结构】
- HDU 5997 rausen loves cakes (启发式合并+树状数组)
- 【HDU 5997】 rausen loves cakes 【启发式合并+线段树】
- HDU 5997 rausen loves cakes (线段树区间维护,启发式区间合并)
- HDU 5997 BestCoder Round #90 1003 rausen loves cakes 线段树 树状数组
- HDU 5997 rausen loves cakes
- hdu 5997 rausen loves cakes
- HDU 5997 rausen loves cakes
- hdu 5997 rausen loves cakes
- HDU5997-rausen loves cakes-树状数组+模拟
- [HDU5997] [BestCoder Round #90] rausen loves cakes启发式合并+线段树
- HDU5997 rausen loves cakes
- 树状数组+启发式合并
- HDU 6133 Army Formations 树状数组 + 启发式合并
- HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
- 【HDU】5197 DZY Loves Orzing 【FFT启发式合并】
- [HDU] 3966 树状数组+启发式树链剖分
- hdu 5196 DZY Loves Inversions(线段树+树状数组+离线+two points)
- Android Camera使用总结与那些坑
- R语言xgboost自定义目标函数
- 【JZOJ3839】Baby Step
- 2 Python 利用socket实现的服务端和客户端
- 找出符合以下条件的Troitsky数,将该数的首位数字移动到末位数字之后得到的数是原数的整数倍 例如:将142857的首位数字1移动到末位之后得到的数是428571,而428571=3*1
- hdu 5997 rausen loves cakes [启发式合并+树状数组/线段数]【杂类+数据结构】
- listview数据刷新分析(三)
- struct device *dev
- SDN关键技术
- Openstack入门过程
- 打包ZIP
- TCP/IP三次握手的详细过程
- MFC picture控件加载透明png图片
- ue4中动画通知的几种方式