[均摊 平衡树 || 线段树] Codeforces 438D #250 (Div. 1) D. The Child and Sequence
2017-01-19 11:41
453 查看
传说中的cf250 china场
题意就是区间取模 区间求和 单点修改
每个数被取模了 肯定会减小一半 一个数最多只要log次就能不动
把相同的数缩成一段
每一段最多被修改O(log n) 次
每一次修改会增加O(1) 段
用平衡树维护 复杂度是 nlog2n 的
对应的势能函数是每一段的log值的和
总势能是(n+m)logn
每次操作log复杂度 能够降1
那么就是两个log的复杂度
等等 这似乎能做这道题加强的区间覆盖版?
是我看错题了 以为是区间覆盖
实际只需要一个线段树 每次找最大的数能%就% 不能就break好了
题意就是区间取模 区间求和 单点修改
每个数被取模了 肯定会减小一半 一个数最多只要log次就能不动
把相同的数缩成一段
每一段最多被修改O(log n) 次
每一次修改会增加O(1) 段
用平衡树维护 复杂度是 nlog2n 的
对应的势能函数是每一段的log值的和
总势能是(n+m)logn
每次操作log复杂度 能够降1
那么就是两个log的复杂度
等等 这似乎能做这道题加强的区间覆盖版?
是我看错题了 以为是区间覆盖
#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=500005; struct node{ int val,cnt,sum,lp,rp; int size; ll ans; node *l,*r,*p,*maxv; node(){ } void newnode(int x,int il,int ir){ lp=il,rp=ir; size=1; sum=cnt=ir-il+1; val=x; ans=(ll)cnt*val; maxv=this; l=r=p=NULL; } void setl(node *x) { l=x; if (x) x->p=this; } void setr(node *x) { r=x; if (x) x->p=this; } void update(){ maxv=this; sum=cnt; size=1; ans=(ll)cnt*val; if (l) { sum+=l->sum,size+=l->size; ans+=l->ans; if (l->maxv->val>maxv->val) maxv=l->maxv; } if (r) { sum+=r->sum,size+=r->size; ans+=r->ans; if (r->maxv->val>maxv->val) maxv=r->maxv; } } }nodes ,*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); return nodes+ncnt; } int mid=(l+r)>>1,t=++ncnt; nodes[t].newnode(a[mid],mid,mid); 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 ; 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),a=nodes+ncnt; if (r+1<=t->rp) nodes[++ncnt].newnode(t->val,r+1,t->rp),b=nodes+ncnt; t->newnode(t->val,l,r); 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),a=nodes+ncnt; t->newnode(t->val,l,t->rp); t=Merge(a,t); if (r+1<=h->rp) nodes[++ncnt].newnode(h->val,r+1,h->rp),b=nodes+ncnt; h->newnode(h->val,h->lp,r); h=Merge(h,b); root=Merge(x.first,Merge(t,Merge(z.first,Merge(h,w.second)))); } int main(){ int Q,order,l,r,w; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); for (int i=1;i<=n;i++) read(a[i]); root=Build(a,1,n); while (Q--){ read(order); 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); printf("%I64d\n",Ans(y.first)); 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); node *t=y.first,*f; while ((f=t->maxv)->val>=w){ f->val%=w; while (f!=t) f->update(),f=f->p; t->update(); } root=Merge(x.first,Merge(y.first,y.second)); }else if (order==3){ read(l); r=l; 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); y.first->val=w; y.first->update(); root=Merge(x.first,Merge(y.first,y.second)); } } return 0; }
实际只需要一个线段树 每次找最大的数能%就% 不能就break好了
#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=100005; int n,a ; inline int Max(int x,int y){ return a[x]>a[y]?x:y; } struct Seg{ int M; int T[N<<2]; ll S[N<<2]; void Build(int n,int *a){ for (M=1;M<n+2;M<<=1); for (int i=1;i<=n;i++) T[M+i]=i,S[M+i]=a[i]; for (int i=M-1;i;i--) T[i]=Max(T[i<<1],T[i<<1|1]),S[i]=S[i<<1]+S[i<<1|1]; } void Modify(int s,int r){ S[s+=M]=r; T[s]=s-M; while (s>>=1) T[s]=Max(T[s<<1],T[s<<1|1]),S[s]=S[s<<1]+S[s<<1|1]; } int Maxv(int s,int t){ ll ret=0; for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){ if (~s&1) ret=Max(ret,T[s^1]); if ( t&1) ret=Max(ret,T[t^1]); } return ret; } ll Sum(int s,int t){ ll ret=0; for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){ if (~s&1) ret+=S[s^1]; if ( t&1) ret+=S[t^1]; } return ret; } }Seg; int main(){ int Q,order,l,r,w; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); for (int i=1;i<=n;i++) read(a[i]); Seg.Build(n,a); while (Q--){ read(order); if (order==1){ read(l); read(r); printf("%I64d\n",Seg.Sum(l,r)); }else if (order==2){ read(l); read(r); read(w); int t; while (a[t=Seg.Maxv(l,r)]>=w){ a[t]%=w; Seg.Modify(t,a[t]); } }else if (order==3){ read(l); read(w); a[l]=w; Seg.Modify(l,w); } } return 0; }
相关文章推荐
- [均摊复杂度线段树]Codeforces 438D. The Child and Sequence
- Codeforces Round #250 (Div. 1) D. The Child and Sequence (线段树)
- Codeforces Round #250 (Div. 1) D. The Child and Sequence(线段树暴力)
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模
- 有趣的线段树小集合 Codeforces Round #250 (Div. 1) D. The Child and Sequence
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树
- codeforces 438D. The Child and Sequence(线段树)
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸
- CF(438D) The Child and Sequence(线段树)
- Codefroces 438D. The Child and Sequence(线段树)
- codeforces438 D The Child and Sequence
- The Child and Sequence(线段树)
- Codeforces Round #250 (Div. 1) D. The Child and Sequence
- 线段树【CF620E】The Child and Sequence
- Codeforces Round #250 (Div. 1) D. The Child and Sequence
- Codeforces Round #250 (Div. 1) D. The Child and Sequence
- CF(438D) The Child and Sequence(线段树)
- Codeforces Round #250 (Div. 1) D. The Child and Sequence
- codeforces --- Round #250 (Div. 2) B. The Child and Set
- codeforces --- Round #250 (Div. 2) A. The Child and Homework