省选测试8

A GCD和LCM

题目大意 : 求满足gcd(i,j)<a的i,j的lcm(i,j)的和

  • 套个莫比乌斯反演,然后把询问离线下来,按a排个序,用树状数组维护即可

Code

Show Code
#include <cstdio>
#include <algorithm>

using namespace std;
const int N = 1e5 + 5, M = 1e9 + 7;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

bool v[N];
int t[N], pri[N], tot, mu[N], ans[N];

struct Node {
    int n, m, a, id;
}q[N];

bool operator < (const Node &x, const Node &y) {
    return x.a < y.a;
}

void Add(int x, int w) {
    for (; x < N; x += x & -x)
        if ((t[x] += w) >= M) t[x] -= M;
}

int Ask(int x, int s = 0) {
    for (; x; x -= x & -x)
        if ((s += t[x]) >= M) s -= M;
    return s;
}

int Sum(int n) {
    return 1ll * n * (n + 1) / 2 % M;
}

int main() {
    mu[1] = 1;
    for (int i = 2; i < N; ++i) {
        if (!v[i]) pri[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot && i * pri[j] < N; ++j) {
            v[i*pri[j]] = 1;
            if (i % pri[j] == 0) break;
            mu[i*pri[j]] = -mu[i];
        }
    }
    int T = read();
    for (int i = 1; i <= T; ++i)
        q[i] = (Node) {read(), read(), read(), i};
    sort(q + 1, q + T + 1);
    for (int k = 1; k <= T; ++k) {
        int n = q[k].n, m = q[k].m, s = 0;
        if (n > m) swap(n, m);
        for (int i = q[k-1].a + 1; i <= q[k].a; ++i)
            for (int j = i; j < N; j += i)
                Add(j, (1ll * j * j / i * mu[j/i] % M + M) % M);
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            if ((s += 1ll * Sum(n / l) * Sum(m / l) % M * (Ask(r) - Ask(l-1) + M) % M) >= M) s -= M; 
        }
        ans[q[k].id] = s;
    }
    for (int i = 1; i <= T; ++i)
        printf("%d\n", ans[i]);
    return 0;
}

B 平面图

题目大意 : 在一个平面图上删边问联通块数量,询问两点是否联通,强制在线

  • 询问联通块数量的话就维护对偶图联通性,每出现一个环就代表有一部分断开,联通块会多一个

  • 询问是否联通的话可以启发式分裂,每次把一个联通块分成两个的时候就给两个同时BFS,把小的块重新编号即可

Code

Show Code
#include <set>
#include <map>
#include <cstdio>
#include <vector>

using namespace std;
const int N = 1e5 + 5;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

set<int> s[N];
vector<int> t[N];
map<int, int> mp[N];
set<int>::iterator it1, it2;
int n, m, tot, f[N*6], ans, c[N], cnt, q1[N], q2[N], v[N];

int Find(int x) {
    return x == f[x] ? x : f[x] = Find(f[x]);
}

int main() {
    n = read(); m = read();
    for (int x = 1; x <= n; ++x) {
        for (int k = read(); k; --k) {
            int y = read();
            s[x].insert(y); t[x].push_back(y);
            mp[x][y] = ++tot; f[tot] = tot;
        }
    }
    //mp[x][y]表示从x到y这条单向边右面的对偶图上点的编号
    for (int x = 1; x <= n; ++x)
        for (int i = 0; i < t[x].size(); ++i)
            f[Find(mp[x][t[x][i]])] = Find(mp[t[x][(i+1)%t[x].size()]][x]);
    cnt = 1;
    while (m--) {
        char od; scanf(" %c", &od);
        int x = read() ^ ans, y = read() ^ ans;
        if (od == '?') printf("%d\n", ans = (c[x] == c[y]));
        else {
            s[x].erase(y); s[y].erase(x);
            int fx = Find(mp[x][y]), fy = Find(mp[y][x]);
            if (fx != fy) f[fx] = fy;
            else {
                int l1, r1, l2, r2;
                v[x] = v[y] = ++tot;
                q1[l1=r1=1] = x; q2[l2=r2=1] = y;
                it1 = s[x].begin(); it2 = s[y].begin(); 
                while (l1 <= r1 && l2 <= r2) {
                    while (l1 <= r1) {
                        if (it1 == s[q1[l1]].end()) it1 = s[q1[++l1]].begin();
                        else if (v[*it1] == tot) ++it1;
                        else { v[*it1] = tot; q1[++r1] = *it1; ++it1; break; }
                    }
                    while (l2 <= r2) {
                        if (it2 == s[q2[l2]].end()) it2 = s[q2[++l2]].begin();
                        else if (v[*it2] == tot) ++it2;
                        else { v[*it2] = tot; q2[++r2] = *it2; ++it2; break; }
                    }
                }
                cnt++;
                if (l1 > l2) for (int i = 1; i <= r1; ++i) c[q1[i]] = cnt;
                else for (int i = 1; i <= r2; ++i) c[q2[i]] = cnt;
            }
            printf("%d\n", ans = cnt);
        }
    }
    return 0;
}

C 路径 (Unaccepted)

题目大意 :

  • 咕了

Code

Show Code
posted @ 2021-02-05 19:36  Shawk  阅读(49)  评论(0编辑  收藏  举报