题意:给出n个点,m条边,每个点都有一个颜色,黑色(用1表示)或白色(用0表示)。有两种操作,一种是询问所有边中满足边的两个点是00,01 or 11这三种情况的边的权值的和,另一种是修改某一点的颜色。
思路:如果直接暴力做的话,每次修改的复杂度达到O(m),考虑分块,对于度数小于lim的点,修改时暴力来做,
对于度数大于lim的点u,用sum[u][0]记录u向外连接颜色为零的边的权值和,然后将所有这些点建一个新图,这样每次只需要维护sum数组即可。这样的话修改和查询的复杂度都为O(sqrt(m))。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
//const int MAXN = 5000000 + 5;
//const int INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
int n;
LL p, k;
set<LL> s;
LL fa[1000100];
int Find(LL x) {
if(x != fa[x]) return fa[x] = Find(fa[x]);
return x;
}
int cnt[1001000];
int main() {
//freopen("input.txt", "r", stdin);
cin >> p >> k;
s.insert(0);
LL ans = 1;
if(k==0) {
for(int i = 1; i < p; i++) ans = ans * p % mod;
cout << ans;
return 0;
}
for(int i = 0; i < p; i++) fa[i] = i;
for(int i = 0; i < p; i++) {
LL shit = k * i % p;
int x1 = Find(i), x2 = Find(shit);
fa[x1] = x2;
}
for(int i = 0; i < p; i++) {
int z = Find(i);
cnt[z]++;
}
for(int i = 1; i < p; i++)
if(cnt[i]) ans = ans * p % mod;
if(k == 1) ans = ans * p % mod;
cout << ans;
return 0;
}