Niuke Practice 68 C- Gráfico não direcionado de Niuniu (MST e contribuição lateral)

 

Limite de tempo: C / C ++ 1 segundo, outros idiomas 2 segundos
Limite de espaço: C / C ++ 262144K, outros idiomas 524288K
64 bits Formato IO:% lld

Descrição do título

Carne com n pontos, sem arestas para a FIG. M, cada lado tem uma aresta direita wiw_iwi

Definimos um peso do caminho é o valor máximo dos pesos das arestas incluídos neste caminho.

A definição d (u, v) representa o peso do caminho com o menor peso entre todos os caminhos do ponto u ao ponto v no gráfico não direcionado
 

Agora Niuniu dá q perguntas, cada vez que um L é dado, perguntando ∑i = 1n∑j = i + 1n [d (i, j) ≤L] \ sum_ {i = 1} ^ n \ sum_ {j = i + 1} ^ n [d (i, j) \ leq L] ∑i = 1n ∑j = i + 1n [d (i, j) ≤L]. Entre eles, [C] significa 1 quando a proposição C é verdadeira, caso contrário, é 0. Por exemplo, [a questão é muito fraca] = 1, [1≥2] = 0 [\ text {a questão é muito fraca}] = 1, [1 \ geq 2] = 0 [a questão é muito fraca] = 1, [1≥2] = 0.

 

Para evitar que a entrada seja muito grande, os jogadores precisam gerar todos os dados a serem inseridos em seu próprio programa. Você pode consultar o seguinte código:

unsigned int SA, SB, SC; int n, m, q, LIM;
unsigned int rng61(){
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}

void gen(){
    scanf("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
    for(int i = 1; i <= m; i++){
        u[i] = rng61() % n + 1;
        v[i] = rng61() % n + 1;
        w[i] = rng61() % LIM;
    }
    for(int i = 1; i <= q; i++){
        L[i] = rng61() % LIM;
    }
}

Os ui, vi, wiu_i, v_i, w_iui, vi, wi gerados representam os atributos da primeira aresta, e LiL_iLi representa o número de entrada na primeira consulta.

 

Digite a descrição:

一行七个正整数 

Descrição de saída:

一行,表示所有答案的异或和。

Exemplo 1

entrar

Cópia 5 7 5 480944053 701657892 339027200 10

5 7 5 480944053 701657892 339027200 10

Resultado

Cópia 1

1

Descrição

 

As cinco perguntas são 7, 4, 0, 4, 9

As respostas são 3, 3, 1, 3, 3

A resposta após XOR é 1.

Observações:

 

1≤n≤105,1≤m, q≤5 × 105,1≤LIM≤1091 \ leq n \ leq 10 ^ 5,1 \ leq m, q \ leq 5 \ vezes 10 ^ 5,1 \ leq LIM \ leq 10 ^ 91≤n≤105,1≤m, q≤5 × 105,1≤LIM≤109

Ideia principal:

Produza o exclusivo ou a soma de todas as consultas.

solução:

Em primeiro lugar, o MST pode minimizar o valor máximo dos pesos das arestas incluídas no caminho , o que é uma propriedade fácil de observar, de modo que este grafo não direcionado é simplificado em várias árvores. Se você deletar todas as arestas da árvore e adicioná-las de volta de acordo com o peso da aresta de pequeno a grande, a contribuição de cada aresta é exatamente o produto do tamanho dos dois conjuntos de pontos, e também pode satisfazer a segunda propriedade, de modo que pode ser resolvido no processo de encontrar MST Para todas as perguntas, as respostas restantes podem ser pré-processadas e dicotomizadas offline.

Código aceito

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 1e5 + 100;
const int M = 5e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

unsigned int SA, SB, SC; int n, m, q, LIM;
unsigned int rng61(){
	SA ^= SA << 16;
	SA ^= SA >> 5;
	SA ^= SA << 1;
	unsigned int t = SA;
	SA = SB;
	SB = SC;
	SC ^= t ^ SA;
	return SC;
}
struct node
{
	ll w;
	int u, v;
	bool operator < (const node &oth) const {
		return w < oth.w;
	}
}a[M];
int f[N], sz[N];
ll val[M], pre[M];

void Init() {
	for (int i = 1; i <= n; i++)
		f[i] = i, sz[i] = 1;
}
int Find(int x) {
	while (x != f[x])
		x = f[x];
	return x;
}
void Merge(int x, int y) {
	x = Find(x);
	y = Find(y);
	if (x == y)
		return;
	if (sz[x] > sz[y])
		swap(x, y);
	f[x] = y, sz[y] += sz[x];
}

int main()
{
	sc("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
	Init();
	for (int i = 1; i <= m; i++) {
		int u = rng61() % n + 1;
		int v = rng61() % n + 1;
		ll w = rng61() % LIM;
		a[i] = { w, u, v };
	}
	sort(a + 1, a + m + 1);

	int k = 0, pos = 0;
	for (int i = 1; i <= m; i++) {
		if (k == n - 1)
			break;
		int u = a[i].u, v = a[i].v;
		if (Find(u) == Find(v))
			continue;
		pos++;
		pre[pos] = pre[pos - 1] + 1ll * sz[Find(u)] * sz[Find(v)];  // 点对数前缀和
		val[pos] = a[i].w;
		Merge(u, v);
	}

	ll ans = 0;
	for (int i = 1; i <= q; i++) {
		int qi = rng61() % LIM;
		int it = upper_bound(val + 1, val + pos + 1, qi) - val; // 二分位置
		ans ^= pre[it - 1];
	}
	printf("%lld\n", ans);
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

 

Acho que você gosta

Origin blog.csdn.net/weixin_43851525/article/details/108287365
Recomendado
Clasificación