BZOJ2038 (莫队)

BZOJ2038: 小Z的袜子

Problem :
N只袜子排成一排,每次询问一个区间内的袜子种随机拿两只袜子颜色相同的概率。
Solution :
莫队算法真的是简单易懂又暴力。
莫队算法用来离线处理区间询问,要求每次区间的端点左右移动1可以直接求出,通过第一关键字分块排序左端点,第二关键字排序右端点,来合理安排询问的顺序,使得总的时间复杂度下降。每次询问直接暴力修改就行。
假设分为k块,每块大小为n/k。
那么左端点移动总的时间复杂度为 n * n / k
右端点移动总的时间复杂度为 k * n + n * k

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <ctime>
using namespace std;
#define f(i, x, y) for (int i = x; i <= y; ++i)
#define fd(i, x, y) for (int i = x; i >= y; --i)
#define rep(i, x, y) for (int i = x; i <= y; ++i)
#define repd(i, x, y) for (int i = x; i >= y; --i)

queue <int> Q;

const int INF = 1e9 + 7;
const int N = 200008;
int n, m, q;

vector <int> vec[N];

int dp[N];
int cnt[N], vis[N];

void init()
{
	srand(time(NULL));
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		vec[i].clear();
	for (int i = 1; i <= m; ++i)
	{
		int u, v;
		cin >> u >> v;
		vec[u].push_back(v);
		vec[v].push_back(u);
	}	
}
void solve()
{	
	for (int i = 1; i <= n; ++i)
		dp[i] = rand() % 4;
	for (int i = 1; i <= n; ++i) Q.push(i), vis[i] = 1;
	while (!Q.empty())
	{
		int u = Q.front(); Q.pop(); vis[u] = 0;
		for (int i = 0; i < 4; ++i) cnt[i] = 0;
		for (auto v : vec[u]) cnt[dp[v]]++;
		if (cnt[dp[u]] <= 1) continue;
	    int qmin = INF, cl = 0;
		for (int i = 0; i < 4; ++i)
			if (cnt[i] < qmin)
			{
				qmin = cnt[i];
				cl = i;
			}	
		dp[u] = cl;
		for (auto v : vec[u])
			if (dp[v] == cl && !vis[v])
				Q.push(v);
	}
	for (int i = 1; i <= n; ++i)
		printf("%c",'a' + dp[i]);
	printf("\n");
}
int main()
{	
	cin.sync_with_stdio(0);
	int T; cin >> T;
	for (int cas = 1; cas <= T; ++cas)
	{
		init();
		solve();
	}
}

posted @ 2017-08-25 14:37  rpSebastian  阅读(188)  评论(0编辑  收藏  举报