[均摊 平衡树 || 线段树] HDU 5634 Rikka with Phi

来源:互联网 发布:nba数据统计排名 编辑:程序博客网 时间:2024/06/05 08:40

用平衡树维护 分析同 [均摊 平衡树 || 线段树] Codeforces 438D #250 (Div. 1) D. The Child and Sequence


#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }  return *p1++;}inline void read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int N=1200005;struct node{  int val,sum,lp,rp; int size; ll ans; int clk;  node *l,*r,*p,*minv;  node(){ }  int cnt() { return rp-lp+1; }  void newnode(int x,int il,int ir,int ic){    lp=il,rp=ir; size=1; sum=ir-il+1; val=x; ans=(ll)cnt()*val; minv=this; l=r=p=NULL; clk=ic;  }  void setl(node *x) { l=x; if (x) x->p=this; }  void setr(node *x) { r=x; if (x) x->p=this; }  void update(){    minv=this; sum=cnt(); size=1; ans=(ll)cnt()*val;    if (l) { sum+=l->sum,size+=l->size; ans+=l->ans; if (l->minv->clk<minv->clk) minv=l->minv; }    if (r) { sum+=r->sum,size+=r->size; ans+=r->ans; if (r->minv->clk<minv->clk) minv=r->minv; }  }}nodes[N],*root;int ncnt;inline int Size(node *x){ return x?x->size:0; }inline int Sum(node *x){ return x?x->sum:0; }inline ll Ans(node *x){ return x?x->ans:0; }inline int ran(){  static int x=31253125; x+=(x<<4)+1; return x&65536;}inline node* Merge(node *A,node *B){  if (!A || !B) return A?A:B;  if (ran()){    node *y=Merge(A->r,B);    A->setr(y); A->update();    return A;  }else{    node *y=Merge(A,B->l);    B->setl(y); B->update();    return B;  }}typedef pair<node*,node* > Droot;inline Droot Split(node *x,int k){  if (!x) return Droot(NULL,NULL);  Droot y;  if(Size(x->l)>=k){    y=Split(x->l,k);    x->setl(y.second); x->update();    if (y.first) y.first->p=NULL;    y.second=x;  }else{    y=Split(x->r,k-Size(x->l)-1);    x->setr(y.first); x->update();    if (y.second) y.second->p=NULL;    y.first=x;  }  return y;}inline int Find(int k){  node *x=root; int ret=0;  while (1){    if (k>Sum(x->l) && k<=Sum(x->l)+x->cnt())      return ret+Size(x->l)+1;    if (Sum(x->l)>=k)      x=x->l;    else      k-=Sum(x->l)+x->cnt(),ret+=1+Size(x->l),x=x->r;  }}inline node *Findkth(int k){  node *x=root;  while (1){    if (k==Size(x->l)+1) return x;    Size(x->l)>=k?x=x->l:(k-=Size(x->l)+1,x=x->r);  }}inline node *Build(int *a,int l,int r){  if (l>r) return NULL;  if (l==r) {    nodes[++ncnt].newnode(a[l],l,r,a[l]==1?1<<30:0);    return nodes+ncnt;  }  int mid=(l+r)>>1,t=++ncnt;  nodes[t].newnode(a[mid],mid,mid,a[mid]==1?1<<30:0);  nodes[t].setl(Build(a,l,mid-1)); nodes[t].setr(Build(a,mid+1,r));  nodes[t].update();  return nodes+t;}int n,a[N];inline void Work(int l,int r){  int lp=Find(l),rp=Find(r);  if (lp==rp){    Droot x=Split(root,lp-1);    Droot y=Split(x.second,1);    node *t=y.first,*a=NULL,*b=NULL;    if (t->lp<=l-1) nodes[++ncnt].newnode(t->val,t->lp,l-1,t->clk),a=nodes+ncnt;    if (r+1<=t->rp) nodes[++ncnt].newnode(t->val,r+1,t->rp,t->clk),b=nodes+ncnt;    t->newnode(t->val,l,r,t->clk);    t=Merge(a,Merge(t,b));    root=Merge(x.first,Merge(t,y.second));    return;  }  Droot x=Split(root,lp-1);  Droot y=Split(x.second,1);  Droot z=Split(y.second,rp-lp-1);  Droot w=Split(z.second,1);  node *t=y.first,*h=w.first,*a=NULL,*b=NULL;  if (t->lp<=l-1) nodes[++ncnt].newnode(t->val,t->lp,l-1,t->clk),a=nodes+ncnt;  t->newnode(t->val,l,t->rp,t->clk); t=Merge(a,t);  if (r+1<=h->rp) nodes[++ncnt].newnode(h->val,r+1,h->rp,h->clk),b=nodes+ncnt;  h->newnode(h->val,h->lp,r,h->clk); h=Merge(h,b);  root=Merge(x.first,Merge(t,Merge(z.first,Merge(h,w.second))));}const int MAXN=1e7+5;const int maxn=1e7;int prime[800005],num;int phi[MAXN];inline void Pre(){  phi[1]=1;  for (int i=2;i<=maxn;i++){    if (!phi[i]) prime[++num]=i,phi[i]=i-1;    for (int j=1;j<=num && (ll)prime[j]*i<=maxn;j++){      if (i%prime[j]==0)phi[i*prime[j]]=phi[i]*prime[j];      elsephi[i*prime[j]]=phi[i]*phi[prime[j]];      if (i%prime[j]==0)break;    }  }}int main(){  int Q,order,l,r,w,T;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  Pre();  read(T);  while (T--){    read(n); read(Q);     for (int i=1;i<=n;i++) read(a[i]);    root=Build(a,1,n);    for (int ti=1;ti<=Q;ti++){      read(order);      if (order==3){read(l); read(r);Work(l,r);int lp=Find(l),rp=Find(r);Droot x=Split(root,lp-1);Droot y=Split(x.second,rp-lp+1);printf("%I64d\n",Ans(y.first));root=Merge(x.first,Merge(y.first,y.second));      }else if (order==1){read(l); read(r);Work(l,r);int lp=Find(l),rp=Find(r);Droot x=Split(root,lp-1);Droot y=Split(x.second,rp-lp+1);node *t=y.first,*f;while ((f=t->minv)->clk<ti){  f->val=phi[f->val]; f->clk=f->val==1?1<<30:ti;  while (f!=t) f->update(),f=f->p; t->update();}root=Merge(x.first,Merge(y.first,y.second));      }else if (order==2){read(l); read(r); read(w);Work(l,r);int lp=Find(l),rp=Find(r);Droot x=Split(root,lp-1);Droot y=Split(x.second,rp-lp+1);nodes[++ncnt].newnode(w,l,r,w==1?1<<30:ti);root=Merge(x.first,Merge(nodes+ncnt,y.second));      }    }    ncnt=0;  }  return 0;}


其实也可以直接上线段树 http://blog.csdn.net/weizhuwyzc000/article/details/50737079

用线段树维护 分析同 [均摊 线段树] UOJ #228. 基础数据结构练习题


0 0