这题我们只需要看出来,对于某个点 u,如果存在 v > u, 且 u->v 之间有边那么我们就一定可以把 u 删掉,翻译过来就是如果 u 的出度(我们默认两个节点之间的边是有向边,节点编号小的 -> 指向编号节点大的节点) > 0 , u 就可以被删去。
因为每次增加或者删去一条边,只会改变一个点的出度,那么我们就可不断的位数 每个节点的出度变化情况,就能快速的得出有多少个点被删掉,那么 n - 被删掉的点 ,就是答案了
代码
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definePirpair<int,int>#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =2e5+10;int n, m;int in[N], out[N];intmain(){scanf("%d %d",&n,&m);int u, v;for(int i =1; i <= m; i ++){scanf("%d %d",&u,&v);if(u > v)swap(u, v);
out[u]++;
in[v]++;}int ans =0;for(int i =1; i <= n; i ++){if(out[i])
ans ++;}int q;scanf("%d",&q);while(q --){int op;scanf("%d",&op);if(op ==1){scanf("%d %d",&u,&v);if(u > v)swap(u, v);if(out[u]==0) ans ++;
out[u]++;
in[v]++;}elseif(op ==2){scanf("%d %d",&u,&v);if(u > v)swap(u, v);if(out[u]==1) ans --;
out[u]--;
in[v]--;}else{printf("%d\n", n - ans);}}return0;}
D. Integers Have Friends
题意
给我们 n 个元素的数组 a [], 让我们找出最长的一段 [l, r],对于这一段存在一个整数 x,x > 1, 且这一段中的所有数取余 x 的余数两两相同。
因此我们可以将问题转化为:把 a [] 中相邻两个数做差,形成一个 新的数组 b [], b [i] = a [i + 1] - a [i] , i <= n - 1。对这个 b [] 数组找出一个最长的一段 [l,r] , 且这一段 gcd (b [l], b [l + 1]…b [r]) != 1,
怎么找这一段呢?我们可以用 rmq 去维护区间 gcd,然后 O (1) 去查询区间 gcd 的值,rmq 预处理复杂度为 n * log (n) , 又因为每次都要 gcd 运算,所以: rmq 预处理复杂度为 n * log (n) * log (n).
还有一种更巧妙的方法:用双指针,去 O (n) 找最长区间 [l, r] , 当双指针指向的区间的 gcd 不为 1 的时候,这个区间是不符合题意的,此时我们必然要移动 左指针 L, 否则的我们继续移动右指针 R 来扩展我们的符合题意的区间的长度,在每次双指针移动的时候都维护答案的最优值,就能得到答案了
代码(rmq + 双指针)
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definePirpair<int,int>#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =2e5+10;
ll n, a[N], b[N], dp[N][20];int mm[N];
ll gcd(ll a, ll b){return b ?gcd(b, a % b): a;}voidinit_rmq(int n){
mm[0]=-1;for(int i =1; i <= n; i ++){
dp[i][0]= b[i];
mm[i]=((i &(i -1))==0)? mm[i -1]+1: mm[i -1];}for(int j =1; j <= mm[n]; j ++){for(int i =1; i +(1<< j)-1<= n; i ++)
dp[i][j]=gcd(dp[i][j -1], dp[i +(1<<(j -1))][j -1]);}}
ll rmq(int x,int y){int k = mm[y - x +1];returngcd(dp[x][k], dp[y -(1<< k)+1][k]);}intmain(){int T;scanf("%d",&T);while(T --){scanf("%lld",&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]);}init_rmq(-- n);int ans =0;int l =1;for(int r =1; r <= n; r ++){while(l <= r &&rmq(l, r)==1) l ++;
ans =max(ans, r - l +1);}printf("%d\n", ans +1);}return0;}
代码(rmq + 二分)
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definePirpair<int,int>#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =2e5+10;
ll n, a[N], b[N], dp[N][20];int mm[N];
ll gcd(ll a, ll b){return b ?gcd(b, a % b): a;}voidinit_rmq(int n){
mm[0]=-1;for(int i =1; i <= n; i ++){
dp[i][0]= b[i];
mm[i]=((i &(i -1))==0)? mm[i -1]+1: mm[i -1];}for(int j =1; j <= mm[n]; j ++){for(int i =1; i +(1<< j)-1<= n; i ++)
dp[i][j]=gcd(dp[i][j -1], dp[i +(1<<(j -1))][j -1]);}}
ll rmq(int x,int y){int k = mm[y - x +1];returngcd(dp[x][k], dp[y -(1<< k)+1][k]);}intmain(){int T;scanf("%d",&T);while(T --){scanf("%lld",&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]);}init_rmq(-- n);int l =1, r = n, ans =1;while(l <= r){int md =(l + r)>>1;int flag =0;for(int i =1; i <= n - md +1; i ++){if(rmq(i, i + md -1)!=1){
flag =1;break;}}if(flag){
ans = md +1;
l = md +1;}else{
r = md -1;}}//要注意:当 n==1 的时时候 ans 的值至少为 1printf("%d\n", ans);}return0;}