题解:P16177 [ICPC 2014 NAIPC] Fantastic Problem
lailai0916 · · 题解
题意简述
维护一个数列。每次单点修改后,求有多少个长度为
解题思路
两个数不互质,当且仅当它们包含相同的质因数。先预处理每个数的所有不同质因数,并为每个质数维护它整除的元素位置集合。
对每个位置
只保留最近的冲突位置不会遗漏答案。若
设长度为
若左端点大于右端点,该贡献为空。反过来,任意非法子段都包含一对不互质的位置
用线段树维护这些区间的覆盖次数,以及覆盖次数为正的总长度。根结点保存的覆盖长度就是当前答案。
修改位置
-
- 对旧值每个质因数,集合中
x 的前驱。 - 对新值每个质因数,集合中
x 的前驱。
先收集这些位置并去重,再从线段树中删除它们原来的贡献。然后更新质因数位置集合和
由于
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=100005;
int n,k,m,lim;
int a[N],nxt[N],pr[N];
bool use[N];
vector<int> fac[N];
set<int> pos[N];
struct SEG
{
int val[N*4],tag[N*4];
void push_up(int u,int l,int r)
{
if(tag[u])val[u]=r-l+1;
else if(l==r)val[u]=0;
else val[u]=val[u*2]+val[u*2+1];
}
void update(int u,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y)tag[u]+=v;
else
{
int mid=l+r>>1;
if(x<=mid)update(u*2,l,mid,x,y,v);
if(y>mid)update(u*2+1,mid+1,r,x,y,v);
}
push_up(u,l,r);
}
}T;
int get_nxt(int i)
{
int res=n+1;
for(auto p:fac[a[i]])
{
auto it=pos[p].upper_bound(i);
if(it!=pos[p].end())res=min(res,*it);
}
return res;
}
void cover(int i,int v)
{
int l=max(1,nxt[i]-k+1),r=min(i,lim);
if(l<=r)T.update(1,1,lim,l,r,v);
}
void collect(int x,int v,int s[],int &cnt)
{
for(auto p:fac[v])
{
auto it=pos[p].lower_bound(x);
if(it!=pos[p].begin())s[cnt++]=*--it;
}
}
void solve()
{
lim=n-k+1;
fill(T.val,T.val+lim*4+5,0);
fill(T.tag,T.tag+lim*4+5,0);
int tot=0;
ll sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
for(auto p:fac[a[i]])
{
if(!use[p])
{
use[p]=1;
pr[tot++]=p;
}
pos[p].insert(i);
}
}
for(int i=1;i<=n;i++)
{
nxt[i]=get_nxt(i);
cover(i,1);
}
cout<<T.val[1]<<'\n';
for(int i=1;i<=m;i++)
{
int x,b;
cin>>x>>b;
int cnt=1;
int s[20];
s[0]=x;
collect(x,a[x],s,cnt);
collect(x,b,s,cnt);
sort(s,s+cnt);
cnt=unique(s,s+cnt)-s;
for(int j=0;j<cnt;j++)cover(s[j],-1);
sum+=b-a[x];
for(auto p:fac[a[x]])pos[p].erase(x);
a[x]=b;
for(auto p:fac[a[x]])
{
if(!use[p])
{
use[p]=1;
pr[tot++]=p;
}
pos[p].insert(x);
}
for(int j=0;j<cnt;j++)
{
nxt[s[j]]=get_nxt(s[j]);
cover(s[j],1);
}
cout<<T.val[1]<<'\n';
}
cout<<sum<<'\n';
for(int i=0;i<tot;i++)
{
pos[pr[i]].clear();
use[pr[i]]=0;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
for(int i=2;i<N;i++)
{
if(!fac[i].empty())continue;
for(int j=i;j<N;j+=i)fac[j].push_back(i);
}
while(cin>>n>>k>>m&&n)solve();
return 0;
}