HDU 5997 rausen loves cakes

问题描述
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个整数nnqq分别表示蛋糕的数目和操作的数目。

接下来一行nn个正整数,第ii个正整数{a}_{i}ai表示第ii个蛋糕的颜色。

接下来qq行,每行3个整数op\left(1\leq op\leq 2 \right)op(1op2)xxyy,描述一个操作
对于op=1op=1,表示rausen进行替换操作,将颜色为xx的蛋糕替换成颜色为yy的蛋糕,xxyy满足\left(1\leq x,y\leq 1000000 \right)(1x,y1000000),请注意xx可能等于yy。

对于op=2op=2,表示rausen进行计数操作,此时你需要输出区间\left[x,y \right][x,y]内颜色的段数,xxyy满足\left(1\leq x\leq y\leq n \right)(1xyn)

\left(1\leq T\leq 5 \right)(1T5)\left(1\leq n\leq {10}^{5} \right)(1n105)\left(1\leq q\leq {10}^{5} \right)(1q105)
输出描述
对于每组测试数据的每一个计数操作,单独输出一行表示答案。
输入样例
1
5 3
1 4 4 10 1
2 1 5
1 4 10
2 3 5
输出样例
4

2

参照题解的做法,替换颜色的时候可以采用启发式合并,把小的往大的里面塞,然后记住每个颜色在当前序列中的颜色,然后维护一个树状数组,统计相邻位置的情况即可。

#include  
#include  
#include  
#include  
#include  
using namespace std;
#define ms(x,y) memset(x,y,sizeof(x))  
#define rep(i,j,k) for(int i=j;i<=k;i++)  
#define loop(i,j,k) for (int i=j;i!=-1;i=k[i])  
#define inone(x) scanf("%d",&x)  
#define intwo(x,y) scanf("%d%d",&x,&y)  
#define inthr(x,y,z) scanf("%d%d%d",&x,&y,&z)  
#define lson x<<1,l,mid  
#define rson x<<1|1,mid+1,r  
typedef long long LL;
const int low(int x) { return x&-x; }
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int T, n, m, x, y, z;
int ft[N], nt[N], u[N], sz;
int f[N], g[N], a[N], q[N];

void add(int x, int y) { for (int i = x; i <= n; i += low(i)) q[i] += y; }

int sum(int x) { int s = 0; for (int i = x; i; i -= low(i)) s += q[i]; return s; }

int main()
{
	inone(T);
	while (T--)
	{
		intwo(n, m);
		ms(ft, -1); ms(f, 0); ms(g, 0); ms(q, 0);
		sz = 0;
		a[0] = a[n + 1] = -1;
		rep(i, 1, n)
		{
			inone(a[i]); f[a[i]] = a[i]; g[a[i]]++;
			u[sz] = i; nt[sz] = ft[a[i]]; ft[a[i]] = sz++;
			if (a[i] != a[i - 1]) add(i, 1);
		}
		while (m--)
		{
			inthr(x, y, z);
			if (x == 2) printf("%d\n", sum(z) - sum(y - 1) + (int)(a[y] == a[y - 1]));
			else
			{
				if (y == z || !g[f[y]]) continue;
				int s = y, t = z;
				if (g[f[y]] > g[f[z]]) swap(y, z);
				y = f[y]; z = f[z];
				loop(i, ft[y], nt)
				{
					if (a[u[i]] != a[u[i] - 1]) add(u[i], -1);
					if (a[u[i]] != a[u[i] + 1]) add(u[i] + 1, -1);
					a[u[i]] = z;
					if (a[u[i]] != a[u[i] - 1]) add(u[i], 1);
					if (a[u[i]] != a[u[i] + 1]) add(u[i] + 1, 1);
					if (nt[i] == -1)
					{
						nt[i] = ft[z]; ft[z] = ft[y]; break;
					}
				}
				g[z] += g[y]; g[y] = 0; f[t] = z; f[s] = 0;
			}
		}
	}
	return 0;
}


你可能感兴趣的:(HDU,----树状数组)