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记得改宏定义!!!
}