# NOIP模拟（10.30）T3 星星

10.30 NOIP模拟T3

Source:

/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>

const int MAXN = 100000 + 10;

int t;
int n, m, x, y;
long long ans;
int low[MAXN];
std::vector<int> edge[MAXN];

struct edges {
int u, v;
} e[MAXN << 1 | 1];

scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) edge[i].clear();
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &x, &y), edge[x].push_back(y), edge[y].push_back(x);
e[i].u = x, e[i].v = y;
}
}

int cnt = 0;
inline void solve_first(int x, int y) {
cnt = 0;
int size = edge[y].size();
for (register int p = edge[x].size() - 1; p >= 0; --p) {
int pos = edge[x][p];
int l = -1, r = size;
while (l + 1 < r) {
int mid = l + r >> 1;
(edge[y][mid] <= pos) ? l = mid : r = mid;
}
cnt += ((~l) && (edge[y][l] == pos));
size = l + 1;
}
}

inline void solve_second(int x, int y) {
cnt = 0;
for (register int p = edge[x].size() - 1, head = edge[y].size() - 1;
p >= 0; --p) {
int pos = edge[x][p];
}
}

inline void solve() {
ans = 0;
for (int i = 1; i <= n; ++i)
std::sort(edge[i].begin(), edge[i].end());
for (int i = 1; i <= m; ++i) {
int x = e[i].u, y = e[i].v;
if (edge[x].size() > edge[y].size()) std::swap(x, y);
(edge[y].size() + edge[x].size() > edge[x].size() *
low[edge[y].size()]) ? solve_first(x, y) : solve_second(x, y);
ans += (cnt ? ((long long)cnt * (long long)(cnt - 1) / 2LL) : 0);
}
std::cout << ans << '\n';
}

int main() {
//	freopen("star.in", "r", stdin);
//	freopen("star.out", "w", stdout);
low[0] = -1;
for (int i = 1; i < MAXN; ++i)
low[i] = (i & i - 1) ? low[i - 1] : low[i - 1] + 1;
scanf("%d", &t);
return 0;
}

1、两个轻点之间的边：显然这样的边的条数为O(m)的，每一次枚举小于sqrt(m)，那么总复杂度为O(m * sqrt(m))

2、重点与轻点之间的边：显然这样的边的条数也是O(m)的，每一次枚举也是小于sqrt(m)的，那么总复杂度依然为O(m * sqrt(m))

3、重点与重点之间的边：首先可以肯定的是，重点的个数在O(sqrt(m))级别，那么显然对于一个重点，它相连的重点的边集的总和一定是小于m的，那么一共有O(sqrt(m))个重点，那么总复杂度还是O(m * sqrt(m))的，那么至此可以证明了，总复杂度为O(m * sqrt(m))，具体的实现可以直接通过将点按照度数排序然后依次枚举即可。

Source:

/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>

const int MAXN = 100000 + 10;

struct point {
int id, degree;
inline bool operator < (const point &a) const {
return degree > a.degree;
}
} p[MAXN];

int n, m, x, y, t;
long long ans = 0;
bool vis[MAXN];
int tag[MAXN];
std::vector<int> edge[MAXN];

scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
edge[i].clear(), p[i].degree = 0, p[i].id = i;
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &x, &y), edge[x].push_back(y), edge[y].push_back(x);
p[x].degree++, p[y].degree++;
}
}

inline void solve() {
memset(vis, false, sizeof(bool) * (n + 1));
memset(tag, 0, sizeof(int) * (n + 1)), ans = 0;
std::sort(p + 1, p + n + 1);
for (int i = 1; i <= n; ++i) {
int cur = p[i].id;
vis[cur] = true;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
tag[v] = cur;
}
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p], cnt = 0;
if (!vis[v]) {
for (int k = 0; k < edge[v].size(); ++k)
if (tag[edge[v][k]] == cur) cnt++;
}
ans += ((long long)cnt * (long long)(cnt - 1)) / 2;
}
}
std::cout << ans << '\n';
}

int main() {
scanf("%d", &t);
return 0;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120