可以发现一个贵族不死亡的条件是没有比它大的贵族直接相连
加减一法维护 ans 即可
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 998244353;
int n, m, ans;
int deg[maxn];
void add(int u, int v)
{
if(u > v) swap(u, v);
ans -= deg[u] == 0;
deg[u]++;
}
void del(int u, int v)
{
if(u > v) swap(u, v);
deg[u]--;
ans += deg[u] == 0;
}
void work()
{
cin >> n >> m;
ans = n;
for(int i = 1; i <= m; ++i)
{
int u, v;scanf("%d %d", &u, &v);
add(u, v);
}
int q;cin >> q;
while(q--)
{
int op, u, v;
scanf("%d", &op);
if(op == 1){
scanf("%d %d", &u, &v); add(u, v);
}
else if(op == 2){
scanf("%d %d", &u, &v); del(u, v);
}
else cout << ans << endl;
}
}
int main()
{
//int T;cin>>T; while(T--)
work();
return 0;
}
D. Integers Have Friends
构造差分数组, st表维护差分数组区间gcd
二分查找以m为起点的最大子区间gcd不为1
数论理论支撑:
就是 (a - b) % m == 0,那么 a 和 b 模 m 同余
假设 a = 26, b = 20, a - b = 6
显然m可以取 1,2,3,6
带进去验证成立
一般来说对m的约束是 m >= 2,所以m可以取2,3,6。(m = 1是同余是显然的)
三个数同余:a = 26,b = 20,c = 5
b - c = 15,m可以取 3,5,15
显然这三个数有共同的公因数3大于1,m可以取3使得三个数同余
我们可以发现,要使n个数同余,只需要让n个数得到的长度为n - 1的差分数组满足相邻数的 gcd 均为 m(m >= 2) 即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 9;
ll n, m, k;
ll f[maxn][25];
ll Log[maxn];
ll d[maxn], a[maxn];
void init()
{
for(int i = 2; i <= maxn - 5; ++i)
Log[i] = Log[i >> 1] + 1;
}
ll query(ll l, ll r)
{
ll s = Log[r - l + 1];
return (ll)__gcd(f[l][s], f[r - (1 << s) + 1][s]);
}
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i)
{
scanf("%lld", &a[i]);
if(i > 1)
d[i-1] = abs(a[i] - a[i - 1]), f[i-1][0] = d[i-1];
}
--n;
for (int j = 1; j <= Log[n]; ++j)
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
f[i][j] = __gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
ll s = 0;
for(ll i = 1; i <= n; ++i)
{
if(f[i][0] == 1) continue;
ll l = i, r = n;
while(l < r)
{
ll m = (l + r + 1) >> 1;
if(query(i, m) == 1) r = m - 1;
else l = m;
}
s = max(s, l - i + 1);
}
cout << s + 1ll << endl;// 求的差分区间长度 +1 就是答案
}
int main()
{
init();
int T;cin >> T;while(T--)
work();
return 0;
}
线段树做法
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 998244353;
ll n, m;
ll a[maxn], b[maxn];
struct SGT
{
ll val[maxn << 2];
#define lc (x << 1)
#define rc (x << 1 | 1)
#define mid ((l + r) >> 1)
void pushup(ll x)
{
val[x] = __gcd(val[lc], val[rc]);
}
void build(ll x, ll l, ll r)
{
if(l == r)
{
val[x] = b[l];return;
}
build(lc, l, mid);
build(rc, mid + 1, r);
pushup(x);
}
ll qry(ll x, ll l, ll r,ll ql, ll qr)
{
if(ql <= l && r <= qr) return val[x];
if(qr < l || r < ql) return 0;
return __gcd(qry(lc, l, mid, ql, qr), qry(rc, mid + 1, r, ql, qr));
}
}T;
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for(int i = 1; i < n; ++i) b[i] = abs(a[i] - a[i + 1]);
if(n == 1){
cout << 1 << endl;return;
}
--n;
T.build(1, 1, n);
ll l = 1, r = 0, ans = 0, now = 0;
while(l <= n)
{
while(r + 1 <= n && __gcd(now, b[r + 1]) > 1)
++r, now = __gcd(now, b[r]);
if(now > 1) ans = max(ans, r - l + 1);
++l;
r = max(r, l - 1);
//if(r < l - 1) ++r; 上句可以改成这句
if(l <= r) now = T.qry(1, 1, n, l, r);// 重新更新l+1到r的gcd
else now = 0;
}
cout << ans + 1ll << endl;
}
int main()
{
int TT;cin>>TT;while(TT--)
work();
return 0;
}