BZOJ2038 (莫隊)

BZOJ2038: 小Z的襪子

Problem :
N只襪子排成一排,每次詢問一個區間內的襪子種隨機拿兩隻襪子顏色相同的機率。
Solution :
莫隊算法真的是簡單易懂又暴力。
莫隊算法用來離線處理區間詢問,要求每次區間的端點左右移動1能夠直接求出,經過第一關鍵字分塊排序左端點,第二關鍵字排序右端點,來合理安排詢問的順序,使得總的時間複雜度降低。每次詢問直接暴力修改就行。
假設分爲k塊,每塊大小爲n/k。
那麼左端點移動總的時間複雜度爲 n * n / k
右端點移動總的時間複雜度爲 k * n + n * kphp

#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();
    }
}
相關文章
相關標籤/搜索