@yang12138
2018-10-27T00:58:42.000000Z
字数 12156
阅读 1192
//二维kd树,询问给定点到已知点集的最短距离,k维同理
//基于欧几里得距离,基于曼哈顿距离同理
const int N=2e5+10;
struct Point{
ll x[2];
Point(){
memset(x,0,sizeof(x));
}
};
ll dis(const Point& a,const Point& b){
ll ans=0;
for(int i=0;i<2;i++) ans+=1LL*(a.x[i]-b.x[i])*(a.x[i]-b.x[i]);
return ans;
}
int DIM;
bool cmp(const Point& a,const Point& b){
return a.x[DIM]<b.x[DIM];
}
ll pw(ll a){return a*a;}
struct Node{
Point p;
int dim;
Node *lson,*rson;
Node(){
lson = rson = NULL;
}
};
Node* newNode(){
return new Node;
}
void build(Node* &root,vector<Point>vec,int dep){
if(!vec.size()){
root=NULL;
return ;
}
root = newNode();
DIM=root->dim=dep;
sort(vec.begin(),vec.end(),cmp);
int sz = (int)vec.size();
root->p = vec[sz/2];
vector<Point>lvec,rvec;
for(int i=0;i<=sz/2-1;i++) lvec.push_back(vec[i]);
for(int i=sz/2+1;i<sz;i++) rvec.push_back(vec[i]);
build(root->lson,lvec,dep^1);
build(root->rson,rvec,dep^1);
}
void add(Node* &root,const Point& tar,int dep){
if(root==NULL){
root=newNode();
root->p=tar,root->dim=dep;
return ;
}
if(tar.x[dep]<=root->p.x[dep])
add(root->lson,tar,dep^1);
else add(root->rson,tar,dep^1);
}
void search(const Node* root,const Point& tar,ll& min_dis){
if(root==NULL) return ;
if(dis(tar,root->p)<min_dis) min_dis=dis(tar,root->p);
Node* left;
if(tar.x[root->dim]<=root->p.x[root->dim]){
search(root->lson,tar,min_dis);
left=root->rson;
}
else{
search(root->rson,tar,min_dis);
left=root->lson;
}
if(pw(abs(tar.x[root->dim] - root->p.x[root->dim]))<=min_dis){
search(left,tar,min_dis);
}
}
//求曼哈顿距离最近和最远
//维护四个最值
struct Point{
int x,y;
Point(){}
Point(int x,int y):x(x),y(y){}
int dis(const Point& tmp)const{
return abs(x-tmp.x)+abs(y-tmp.y);
}
};
int DIM;
bool cmp(const Point& a,const Point& b){
return DIM?a.y<b.y:a.x<b.x;
}
struct Node{
Point p;
Node *lson,*rson;
int mi[2],ma[2];
Node(){
lson = rson = NULL;
}
void setp(const Point& tp){
this->p = tp;
mi[0]=ma[0]=tp.x;
mi[1]=ma[1]=tp.y;
}
void pushup(const Node& tp){
mi[0]=min(mi[0],tp.mi[0]);
ma[0]=max(ma[0],tp.ma[0]);
mi[1]=min(mi[1],tp.mi[1]);
ma[1]=max(ma[1],tp.ma[1]);
}
//求理论上可能的最小值
int min_dis(const Point& tp){
int ans=0;
if(tp.x<mi[0] || tp.x>ma[0]){
ans+= (tp.x<mi[0])?mi[0]-tp.x:tp.x-ma[0];
}
if(tp.y<mi[1] || tp.y>ma[1]){
ans+= (tp.y<mi[1])?mi[1]-tp.y:tp.y-ma[1];
}
return ans;
}
//求理论上可能的最大值
int max_dis(const Point& tp){
return max(abs(tp.x-mi[0]),abs(tp.x-ma[0]))+max(abs(tp.y-mi[1]),abs(tp.y-ma[1]));
}
};
//[l,r)
void build(Node* &root,Point* p,int l,int r,int dep){
if(l>=r){
root=NULL;
return ;
}
root = new Node;
int sz=r-l;
DIM = dep;
nth_element(p+l,p+l+sz/2,p+r,cmp);
root->setp(p[l+sz/2]);
build(root->lson,p,l,l+sz/2,dep^1);
build(root->rson,p,l+sz/2+1,r,dep^1);
if(root->lson!=NULL) root->pushup(*(root->lson));
if(root->rson!=NULL) root->pushup(*(root->rson));
}
void search_min(Node* &root,const Point& tar,int dep,int& ans){
if(root==NULL) return ;
if(root->p.dis(tar)!=0) ans=min(ans,root->p.dis(tar));
if(root->lson==NULL && root->rson==NULL) return ;
if(root->lson==NULL){
search_min(root->rson,tar,dep+1,ans);
}
else if(root->rson==NULL){
search_min(root->lson,tar,dep+1,ans);
}
else{
if(root->lson->min_dis(tar) < root->rson->min_dis(tar)){
if(root->lson->min_dis(tar)>=ans) return ;
search_min(root->lson,tar,dep+1,ans);
if(root->rson->min_dis(tar)<ans) search_min(root->rson,tar,dep+1,ans);
}
else{
if(root->rson->min_dis(tar)>=ans) return ;
search_min(root->rson,tar,dep+1,ans);
if(root->lson->min_dis(tar)<ans) search_min(root->lson,tar,dep+1,ans);
}
}
}
void search_max(Node* &root,const Point& tar,int dep,int& ans){
if(root==NULL) return ;
ans=max(ans,root->p.dis(tar));
if(root->lson==NULL && root->rson==NULL) return ;
if(root->lson==NULL){
search_max(root->rson,tar,dep+1,ans);
}
else if(root->rson==NULL){
search_max(root->lson,tar,dep+1,ans);
}
else{
if(root->lson->max_dis(tar) > root->rson->max_dis(tar)){
if(root->lson->max_dis(tar)<=ans) return ;
search_max(root->lson,tar,dep+1,ans);
if(root->rson->max_dis(tar)>ans) search_max(root->rson,tar,dep+1,ans);
}
else{
if(root->rson->max_dis(tar)<=ans) return ;
search_max(root->rson,tar,dep+1,ans);
if(root->lson->max_dis(tar)>ans) search_max(root->lson,tar,dep+1,ans);
}
}
}
可求素数之和
时间,空间大概
struct HashTable{
const static int N = 6.6e5+10;
const static int mod = (1<<22)+1;
int head[mod];
int v[N],nex[N],cnt;
ll u[N];
HashTable(){
memset(head,0,sizeof(head));
cnt=1;
}
void insert(ll x,int id){
int left=x%mod;
v[cnt]=id,u[cnt]=x,nex[cnt]=head[left],head[left]=cnt++;
}
int query(ll x){
int left=x%mod;
for(int i=head[left];i;i=nex[i]){
if(u[i]==x) return v[i];
}
return -1;
}
void clear(){
memset(head,0,sizeof(head));
cnt=1;
}
}ht;
const int N=6.6e5+10;
int pri[N],t;
ll pris[N];
bool vis[N];
void init(){
for(int i=2;i<N;i++){
if(!vis[i]) pri[++t]=i;
for(int j=1;j<=t;j++){
int u=pri[j]*i;
if(u>=N) break;
vis[u]=1;
if(i%pri[j]==0) break;
}
}
for(int i=1;i<=t;i++) pris[i]=pris[i-1]+pri[i];
}
int Hash(int x){
return upper_bound(pri+1,pri+t+1,x)-pri-1;
}
int sqr(ll x){
int k=(int)sqrt(x+0.5);
while(1LL*(k+1)*(k+1)<=x) k++;
while(1LL*k*k>x) k--;
return k;
}
int cou[N];
ll v[N];
double *dp[N];
int len[N];
double g(ll n,int j){
if(j==0) return 1.0*n*(n+1)/2-1;
int id=ht.query(n);
if(j>len[id]) return g(n,len[id]);
if(dp[id]==NULL){
dp[id]=new double[len[id]+1];
for(int i=0;i<len[id]+1;i++) dp[id][i]=-1.0;
}
if(dp[id][j]>=0) return dp[id][j];
return dp[id][j]=g(n,j-1)-1.0*pri[j]*(g(n/pri[j],j-1)-pris[j-1]);
}
double cal(ll n){
if(n<=1) return 0;
ht.clear();
int cnt=0;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
v[++cnt]=n/l;
len[cnt]=Hash(sqr(n/l));
ht.insert(n/l,cnt);
}
double ans=g(n,t);
for(int i=1;i<=cnt;i++){
if(dp[i]!=NULL) delete(dp[i]),dp[i]=NULL;
}
return ans;
}
定义是积性函数
求
struct HashTable{
const static int N = 2.1e5+10;
const static int mod = (1<<20)+1;
int head[mod];
int v[N],nex[N],cnt;
ll u[N];
HashTable(){
memset(head,0,sizeof(head));
cnt=1;
}
void insert(ll x,int id){
int left=x%mod;
v[cnt]=id,u[cnt]=x,nex[cnt]=head[left],head[left]=cnt++;
}
int query(ll x){
int left=x%mod;
for(int i=head[left];i;i=nex[i]){
if(u[i]==x) return v[i];
}
return -1;
}
void clear(){
memset(head,0,sizeof(head));
cnt=1;
}
}ht;
const int N=2.1e5+10;
const int mod=1e9+7;
struct PLL{
int a;
ll b;
PLL(){
a=b=-1;
}
PLL(ll a,ll b):a(a),b(b){}
PLL operator - (const PLL& tmp)const{
return PLL((0LL+a-tmp.a+mod)%mod,b-tmp.b);
}
PLL operator + (const PLL& tmp)const{
return PLL((0LL+a+tmp.a)%mod,b+tmp.b);
}
PLL operator * (const PLL& tmp)const{
return PLL((1LL*a*tmp.a)%mod,b*tmp.b);
}
}pris[N];
int pri[N],t;
bool vis[N];
ll ps[N];
void init(){
for(int i=2;i<N;i++){
if(!vis[i]) pri[++t]=i;
for(int j=1;j<=t;j++){
int u=pri[j]*i;
if(u>=N) break;
vis[u]=1;
if(i%pri[j]==0) break;
}
}
pris[0]=PLL(0,0);
for(int i=1;i<=t;i++){
pris[i]=pris[i-1]+PLL(pri[i],1);
ps[i]=(ps[i-1]+(pri[i]^1))%mod;
}
}
int Hash(int x){
return upper_bound(pri+1,pri+t+1,x)-pri-1;
}
int sqr(ll x){
int k=(int)sqrt(x+0.5);
while(1LL*(k+1)*(k+1)<=x) k++;
while(1LL*k*k>x) k--;
return k;
}
int len[N];
ll v[N];
int *dpa[N];
ll *dpb[N];
PLL h(ll n,int j){
if(j==0) return PLL((1LL*(n%mod)*(n%mod+1)/2-1)%mod,n-1);
int id=ht.query(n);
if(j>len[id]) return h(n,len[id]);
if(dpa[id]==NULL){
dpa[id] = new int[len[id]+1];
dpb[id] = new ll[len[id]+1];
for(int i=0;i<len[id]+1;i++) dpa[id][i]=-1,dpb[id][i]=-1;
}
if(dpa[id][j]>=0) return PLL(dpa[id][j],dpb[id][j]);
PLL ans=h(n,j-1)-PLL(pri[j],1)*(h(n/pri[j],j-1)-pris[j-1]);
dpa[id][j]=ans.a,dpb[id][j]=ans.b;
return ans;
}
void initn(ll n){
ht.clear();
int cnt=0;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
v[++cnt]=n/l;
len[cnt]=Hash(sqr(n/l));
ht.insert(n/l,cnt);
}
}
//[1,n] \sigma_{p is prime}f(p)
ll cal(ll n){
if(n<=1) return 0;
PLL ans=h(n,t);
return (0LL+ans.a+1-(ans.b-1))%mod;
}
int *G[N];
ll g(ll n,int m){
if(m>=1 && pri[m]>=n) return 0;
if(m>=1 && n/pri[m]<=pri[m]){
return (cal(n)-ps[m]+mod)%mod;
}
int id=ht.query(n);
if(G[id]==NULL){
G[id] = new int[len[id]+1];
for(int i=0;i<len[id]+1;i++) G[id][i]=-1;
}
if(G[id][m]>=0) return G[id][m];
ll ans=0;
for(int i=m+1;1LL*pri[i]*pri[i]<=n;i++){
ll cur=pri[i];
for(int j=1;cur<=n;j++){
ll tmp=g(n/cur,i)+((j>1)?1:0);
(ans+=(pri[i]^j)*tmp)%=mod;
cur*=pri[i];
}
}
(ans+=cal(n)-ps[m])%=mod;
return G[id][m]=ans;
}
void solve(ll n){
initn(n);
ll ans=g(n,0);
cout<<(ans+1+mod)%mod<<endl;
}
平衡树,可以实现区间翻转
struct Node{
ll x,mi,tag;
int sz;
bool rev;
Node *ch[2],*fa;
Node(){}
Node(ll x,Node* fa):x(x),fa(fa){
ch[0] = ch[1] = NULL;
mi = x,tag = 0,rev = 0,sz = 1;
}
void pushup(){
mi = x,sz = 1;
if(ch[0]!=NULL) mi = min(mi, ch[0]->mi),sz+=ch[0]->sz;
if(ch[1]!=NULL) mi = min(mi, ch[1]->mi),sz+=ch[1]->sz;
}
};
//如果u是它父亲的左儿子return 0,否则return 1
int son(Node* u){
return (u->fa->ch[1] == u);
}
//d=0 表示左旋
void rotate(Node* root,int d){
Node *f = root->fa;
f->ch[d^1] = root->ch[d];
if(root->ch[d]!=NULL) root->ch[d]->fa=f;
root->fa = f->fa;
if(f->fa!=NULL) f->fa->ch[son(f)]=root;
f->fa = root;
root->ch[d] = f;
f->pushup(),root->pushup();
}
//把root旋转到s的儿子,rt是根节点
void splay(Node *root,Node *s,Node* &rt){
while(root->fa != s){
Node *f = root->fa;
/*
rotate(root,son(root)^1);
continue;
*/
if(f->fa == s){
rotate(root,son(root)^1);
break;
}
else if(son(root) == son(root->fa)){
int d = son(root);
rotate(root->fa,d^1);
rotate(root,d^1);
}
else{
int d = son(root);
rotate(root,d^1);
rotate(root,d);
}
}
if(s==NULL) rt = root;
}
void pushdown(Node* &root){
if(root->rev){
swap(root->ch[0],root->ch[1]);
}
if(root->ch[0]!=NULL){
root->ch[0]->rev ^= root->rev;
root->ch[0]->x += root->tag;
root->ch[0]->mi += root->tag;
root->ch[0]->tag += root->tag;
}
if(root->ch[1]!=NULL){
root->ch[1]->rev ^= root->rev;
root->ch[1]->x += root->tag;
root->ch[1]->mi += root->tag;
root->ch[1]->tag += root->tag;
}
root->rev = 0;
root->tag = 0;
}
const int N=2e5+10;
Node node[N];
int cnt;
Node* newNode(ll x,Node* f){
node[cnt]=Node(x,f);
return &node[cnt++];
}
ll a[N];
void build(Node* &root,int l,int r,Node* f){
if(l>r) return ;
int m=(l+r)>>1;
root = newNode(a[m],f);
build(root->ch[0],l,m-1,root);
build(root->ch[1],m+1,r,root);
root->pushup();
}
//找到序列中第x个数并将它伸展到s的儿子
void search(Node* &cur,int x,Node* s,Node* &rt){
pushdown(cur);
int lsz = (cur->ch[0]==NULL)?0:cur->ch[0]->sz;
if(lsz >= x) search(cur->ch[0],x,s,rt);
else if(x == lsz+1){
splay(cur,s,rt);
return ;
}
else search(cur->ch[1],x-1-lsz,s,rt);
}
//处理[l,r]区间,使第l-1个数在根节点,第r+1个数在根节点的右儿子
void process(Node* &root,int l,int r){
search(root,l,NULL,root);
search(root,r+2,root,root);
}
//[l,r]区间加d
void add(Node* &root,int l,int r,int d){
process(root,l,r);
Node* k = root->ch[1]->ch[0];
k->x += d;
k->mi += d;
k->tag += d;
}
//翻转[l,r]区间
void reverse(Node* &root,int l,int r){
process(root,l,r);
root->ch[1]->ch[0]->rev ^= 1;
}
//[l,r]区间左移cnt次
void revolve(Node* &root,int l,int r,int cnt){
cnt %= (r-l+1);
if(!cnt) return ;
reverse(root,l,r);
reverse(root,l,l+cnt-1);
reverse(root,l+cnt,r);
}
//第x个数后面添加一个数p
void insert(Node* &root,int x,ll p){
search(root,x+1,NULL,root);
pushdown(root);
if(root->ch[1]==NULL){
root->ch[1] = newNode(p,root);
root->pushup();
return ;
}
Node* k = root->ch[1];
while(1){
pushdown(k);
if(k->ch[0]==NULL) break;
k=k->ch[0];
}
splay(k,root,root);
k->ch[0] = newNode(p,k);
k->pushup(),root->pushup();
}
//删掉第x个数
void del(Node* &root,int x){
search(root,x+1,NULL,root);
pushdown(root);
if(root->ch[1]==NULL){
root = root->ch[0];
root->fa = NULL;
return ;
}
Node* k = root->ch[1];
while(1){
pushdown(k);
if(k->ch[0]==NULL) break;
k=k->ch[0];
}
splay(k,root,root);
k->ch[0] = root->ch[0];
if(k->ch[0]!=NULL) k->ch[0]->fa = k;
root->ch[0] = NULL;
root = k;
if(root!=NULL) root->fa=NULL;
}
//[l,r]区间最小值
ll min(Node* &root,int l,int r){
process(root,l,r);
pushdown(root);
pushdown(root->ch[1]);
pushdown(root->ch[1]->ch[0]);
return root->ch[1]->ch[0]->mi;
}
//中序遍历splay
void dfs(Node* root,vector<int>& ans){
if(root==NULL) return ;
pushdown(root);
dfs(root->ch[0],ans);
ans.push_back(root->x);
dfs(root->ch[1],ans);
}
平衡树,比多一个求名次功能
//通过赋予每个插入平衡树中的节点一个随机权值,在插入后根据权值进行旋转操作(类似堆的更新),树高O(logn)
struct Node{
int x,rk,sz;
Node *ch[2];
Node(int x):x(x){
ch[0] = ch[1] = NULL;
rk = rand();sz = 1;
}
int cmp(const int& y){
if(x==y) return -1;
return x<y?0:1;
}
void pushup(){
sz=1;
if(ch[0]!=NULL) sz+=ch[0]->sz;
if(ch[1]!=NULL) sz+=ch[1]->sz;
}
};
void rotate(Node* &root,int d){
Node* k=root->ch[d^1];
root->ch[d^1]=k->ch[d];
k->ch[d]=root;
root->pushup();k->pushup();
root=k;
}
//在树上插入x,可重复
void add(Node* &root,int x){
if(root == NULL){
root = new Node(x);
return ;
}
int d=root->cmp(x);
if(d==-1) d=0;
add(root->ch[d^1],x);
if(root->rk < root->ch[d^1]->rk) rotate(root,d);
root->pushup();
}
//在树上删除x,重复的只删除一个
void remove(Node* &root,int x){
if(root==NULL) return ;
int d=root->cmp(x);
if(d==-1){
Node* k = root;
if(root->ch[0] == NULL){
root = root->ch[1];
delete(k);
}
else if(root->ch[1] == NULL){
root = root->ch[0];
delete(k);
}
else{
int d = (root->ch[0]->rk < root->ch[1]->rk) ? 0 : 1;
rotate(root,d);
remove(root->ch[d],x);
}
}
else remove(root->ch[d^1],x);
if(root!=NULL) root->pushup();
}
//判断树上有没有x
bool has(Node* &root,int x){
if(root==NULL) return 0;
int d = root->cmp(x);
if(d==-1) return 1;
return has(root->ch[d^1],x);
}
//集合第k大
int kth(Node* &root,int k){
if(k<=0) return 0;
// not exist
if(root == NULL) return 0;
if(root->sz < k) return 0;
int rsz = (root->ch[1]==NULL)?0:root->ch[1]->sz;
if(rsz >= k) return kth(root->ch[1],k);
else if(rsz+1 == k) return root->x;
else return kth(root->ch[0],k-1-rsz);
}
void removetree(Node* &root){
if(root==NULL) return ;
removetree(root->ch[0]);
removetree(root->ch[1]);
delete(root);
root=NULL;
}