@yang12138
2018-10-26T16:58:42.000000Z
字数 12156
阅读 1443
//二维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 1int 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]区间加dvoid 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个数后面添加一个数pvoid 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;}//中序遍历splayvoid 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();}//判断树上有没有xbool 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 existif(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;}