Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 rausen喜欢吃蛋糕。某天,他买了nn个蛋糕,每个蛋糕都有一个颜色,用\left[1,1000000 \right][1,1000000]中的整数来表示。rausen将它们从左到右排成一行,然后准备开始吃。
# include <bits/stdc++.h> using namespace std; typedef long long int LL ; /***********************************************************************/ const int N = 1000000 + 5; //数列的大小 int ft[N]; //ft[a]=b 是a这个颜色最后一次出现的位置是b int nt[N]; //nt[a]=b 是a这个位置的颜色上一次出现过的地方是b(因为修改 所以可能是乱序的,但是最终都是连在一起的) int u[N]; //ft[],nt[] 维护的是一种颜色链之间的关系,所以我们需要一个u[]来表示在最初的位置 int cnt,n,q; //略 int f[N]; //f[a]=b ,颜色号为a的颜色 现在代表颜色b int 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;