【雜題】[BZOJ4320]【ShangHai2006】Homework【平衡規劃】【並查集】
阿新 • • 發佈:2018-12-18
Description
需要支援兩種操作 1:在人物集合 S 中加入一個新的程式設計師,其代號為 X,保證 X 在當前集合中不存在。 2:在當前的人物集合中詢問程式設計師的mod Y 最小的值。 (為什麼統計這個?因為拯救 過世界的人太多了,只能取模) 保證第一次為操作1 N≤100000, 1≤X,Y≤300000
Solution
直接統計,很難辦 可以用平衡規劃的思想搞一波 令 對於所有的詢問,我們在修改時暴力將這些詢問更新即可,然後直接查詢。
對於所有的詢問,我們可以離線,將詢問和修改倒過來,用並查集維護右邊的第一個是誰,對於每個詢問直接列舉倍數即可(當然也可以值域分塊,相當於區間查詢最小值)。 複雜度
Code
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 300005
using namespace std;
int mx,n,ri[N],ask[N][2],ans[N],qs[550];
int fd(int k)
{
if(ri[k]==k) return k;
if(!ri[k]) return 0;
return ri[k]=fd(ri[k]);
}
int main()
{
cin>>n;
mx=0;
memset(qs,107,sizeof(qs));
fo(i,1,n)
{
char ch;
int x;
scanf("\n%c %d",&ch,&x);
ask[i][0]=ch-'A';
ask[i][1]=x;
if (ch=='A') mx=max(mx,x),ri[x]=x;
}
int n1=sqrt(mx);
memset(ans,107,sizeof(ans));
fo(i,1,n)
{
if(ask[i][0]==0) fo(j,1,n1) qs[j]=min(qs[j],ask[i][1]%j);
else if(ask[i][1]<=n1) ans[i]=qs[ask[i][1]];
}
fod(i,mx,0) if(!ri[i]) ri[i]=ri[i+1];
fod(i,n,1)
{
if(!ask[i][0]) ri[ask[i][1]]=fd(ask[i][1]+1);
else if(ask[i][1]>n1)
{
for(int j=0;ask[i][1]*j<=mx;j++)
{
int p=fd(ask[i][1]*j);
if(p) ans[i]=min(ans[i],p%ask[i][1]);
}
}
}
fo(i,1,n) if(ask[i][0]==1) printf("%d\n",ans[i]);
}