跟随着潮流,弱弱的学习了一下主席树。明白了思想之后,第一次比较快的自己写出了代码。小专题
cogs930找第K小的数||1534K大数
题目大意:静态区间第K小的查询。
思路:裸裸的主席树模板题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node{ Node *ch[2]; int a,siz; Node (){ch[0]=ch[1]=NULL;siz=a=0;} void updata(){ siz=a; if (ch[0]!=NULL) siz+=ch[0]->siz; if (ch[1]!=NULL) siz+=ch[1]->siz; } }*null=new Node(),*root[100001]={NULL},q[2000001]; int a[100001]={0},a2[100001]={0},q_size=0; void insert(Node *&y,Node *&x,int l,int r,int xx) { int mid; if (x==NULL) x=null; y=&q[++q_size]; *y=Node(); if (l==r) { *y=*x; y->siz++;y->a++; return; } mid=(l+r)/2; if (xx<=a2[mid]) { insert(y->ch[0],x->ch[0],l,mid,xx); y->ch[1]=x->ch[1]; y->updata(); } else { insert(y->ch[1],x->ch[1],mid+1,r,xx); y->ch[0]=x->ch[0]; y->updata(); } } void find(Node *&x2,Node *&x1,int l,int r,int k) { int ss=0,mid; if (x2==NULL) x2=null; if (x1==NULL) x1=null; if (l==r) { printf("%d\n",a2[l]); return; } mid=(l+r)/2; if (x2->ch[0]!=NULL) ss+=x2->ch[0]->siz; if (x1->ch[0]!=NULL) ss-=x1->ch[0]->siz; if (ss>=k) find(x2->ch[0],x1->ch[0],l,mid,k); else find(x2->ch[1],x1->ch[1],mid+1,r,k-ss); } int main() { freopen("kth.in","r",stdin); freopen("kth.out","w",stdout); int n,m,i,j,k,l,r; null->ch[0]=null;null->ch[1]=null; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) { scanf("%d",&a[i]); a2[i]=a[i]; } sort(a2+1,a2+n+1); int size; size=unique(a2+1,a2+n+1)-a2-1; for (i=1;i<=n;++i) insert(root[i],root[i-1],1,size,a[i]); for (i=1;i<=m;++i) { scanf("%d%d%d",&l,&r,&k); find(root[r],root[l-1],1,size,k); } fclose(stdin); fclose(stdout); }
cogs257动态排名系统
题目大意:动态区间第K小的查询
思路:裸裸的动态主席。。。在原来的主席树外面套一个树状数组,然后就可以了。
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<iostream> #include<cstring> using namespace std; struct use{ int l,r,siz; }tree[10000001]={0}; struct use1{ int xx,yy,kk; }qq[10001]={0}; int root[50001]={0},a[50001]={0},a2[60001]={0},q1[2000]={0},q2[2000]={0},tot=0,size,n; char ch[10001]; int lowbit(int x){return x&-x;} void build(int &x,int l,int r) { int mid; tree[x=++tot].siz=0; if (l==r) return; mid=(l+r)/2; build(tree[x].l,l,mid); build(tree[x].r,mid+1,r); } void ins(int last,int &i,int l,int r,int x,int flag) { tree[i=++tot].siz=tree[last].siz+flag; tree[i].l=tree[last].l;tree[i].r=tree[last].r; if (l==r) return; int mid=(l+r)/2; if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag); else ins(tree[last].r,tree[i].r,mid+1,r,x,flag); } void bit_ins(int i,int x,int flag) { for (;i<=n;i+=lowbit(i)) ins(root[i],root[i],1,size,x,flag); } int ask(int l,int r,int k) { int ss=0,i,j,mid; if (l==r) return l; for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz; for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz; mid=(l+r)/2; if (ss>=k) { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l; return ask(l,mid,k); } else { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r; return ask(mid+1,r,k-ss); } } int bit_ask(int l,int r,int k) { q1[0]=q2[0]=0; for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l]; for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r]; return ask(1,size,k); } int main() { freopen("dynrank.in","r",stdin); freopen("dynrank.out","w",stdout); int m,i,j,d; scanf("%d",&d); while(d) { scanf("%d%d",&n,&m); tot=0;a2[0]=0; memset(tree,0,sizeof(tree)); memset(root,0,sizeof(root)); for (i=1;i<=n;++i) { scanf("%d",&a[i]); ++a2[0];a2[a2[0]]=a[i]; } for (i=1;i<=m;++i) { scanf("%*c%c%d%d",&ch[i],&qq[i].xx,&qq[i].yy); if (ch[i]=='Q') scanf("%d",&qq[i].kk); else a2[++a2[0]]=qq[i].yy; } sort(a2+1,a2+a2[0]+1); size=unique(a2+1,a2+a2[0]+1)-a2-1; build(root[0],1,size); for (i=1;i<=n;++i) { a[i]=upper_bound(a2+1,a2+size+1,a[i])-a2-1; bit_ins(i,a[i],1); } for (i=1;i<=m;++i) { if (ch[i]=='Q') { j=bit_ask(qq[i].xx-1,qq[i].yy,qq[i].kk); printf("%d\n",a2[j]); } else { bit_ins(qq[i].xx,a[qq[i].xx],-1); a[qq[i].xx]=upper_bound(a2+1,a2+size+1,qq[i].yy)-a2-1; bit_ins(qq[i].xx,a[qq[i].xx],1); } } --d; } fclose(stdin); fclose(stdout); }
cogs1715||bzoj3295动态逆序对
题目大意:每次删除一个数,输出删除前逆序对的总个数。
思路:用的动态主席,倒着来做,ask略有不同,然后很开心的re了,之后NU刷cogs。。。MLE了一片。。。
#include<iostream> #include<cstdio> using namespace std; struct use{ int l,r,siz; }tree[10000000]; int root[100001]={0},a[100001]={0},num[100001]={0},a2[100001]={0},del[50001]={0},q1[2000]={0},q2[2000]={0}, cc[100001]={0},tot=0,n; long long ansi[50001]={0}; int lowbit(int x) {return x&(-x);} int work(int l,int r) { int mid,ans=0,i,j; if (l==r) return ans; mid=(l+r)/2; ans+=work(l,mid)+work(mid+1,r); cc[0]=0;i=l;j=mid+1; while(i<=mid&&j<=r) { if (a2[i]<a2[j]) { cc[++cc[0]]=a2[i];++i; } else { cc[++cc[0]]=a2[j];++j; ans+=mid-i+1; } } for (;i<=mid;++i) cc[++cc[0]]=a2[i]; for (;j<=r;++j) cc[++cc[0]]=a2[j]; for (i=l;i<=r;++i) a2[i]=cc[i-l+1]; return ans; } void build(int &x,int l,int r) { int mid; tree[x=++tot].siz=0; if (l==r) return; mid=(l+r)/2; build(tree[x].l,l,mid); build(tree[x].r,mid+1,r); } void ins(int last,int &i,int l,int r,int x,int flag) { int mid; tree[i=++tot].siz=tree[last].siz+flag; tree[i].l=tree[last].l;tree[i].r=tree[last].r; if (l==r) return; mid=(l+r)/2; if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag); else ins(tree[last].r,tree[i].r,mid+1,r,x,flag); } void bit_ins(int i,int x,int flag) { for (;i<=n;i+=lowbit(i)) ins(root[i],root[i],1,n,x,flag); } long long ask(int l,int r,int x,int flag) { long long ss=0; int mid,i; if (l==r) return 0; mid=(l+r)/2; if (flag==0) { ss=0; for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz; for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz; if (x<=mid) { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l; return ask(l,mid,x,flag); } else { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r; return ss+ask(mid+1,r,x,flag); } } else { ss=0; for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].r].siz; for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].r].siz; if (x<=mid) { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l; return ss+ask(l,mid,x,flag); } else { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r; return ask(mid+1,r,x,flag); } } } long long bit_ask(int l,int r,int x,int flag) { q1[0]=q2[0]=0; for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l]; for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r]; return ask(1,n,x,flag); } int main() { freopen("inverse.in","r",stdin); freopen("inverse.out","w",stdout); int m,i,j,k; long long ans=0; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) { scanf("%d",&a[i]); num[a[i]]=i; } for (i=m;i>=1;--i) { scanf("%d",&del[i]); a[num[del[i]]]=0; } build(root[0],1,n); for (i=1;i<=n;++i) if (a[i]) { a2[++a2[0]]=a[i]; bit_ins(i,a[i],1); } ans=work(1,a2[0]); for (i=1;i<=m;++i) { k=del[i];j=num[k];a[j]=k; bit_ins(j,k,1); if (j>1) ans+=bit_ask(0,j-1,k,1); if (j<n) ans+=bit_ask(j,n,k,0); ansi[i]=ans; } for (i=m;i>=1;--i) printf("%I64d\n",ansi[i]); fclose(stdin); fclose(stdout); }
终于发现re的原因了,其实之前写的主席树一直有一些漏洞,每次插入一个点的时候都会新建很多节点,其实有的节点是可以直接用原来的就可以了。
#include<iostream> #include<cstdio> using namespace std; struct use{ int l,r,siz; }tree[10000000]; int root[100001]={0},a[100001]={0},num[100001]={0},a2[100001]={0},del[50001]={0},q1[2000]={0},q2[2000]={0}, cc[100001]={0},tot=0,n; long long ansi[50001]={0}; int lowbit(int x) {return x&(-x);} int work(int l,int r) { int mid,ans=0,i,j; if (l==r) return ans; mid=(l+r)/2; ans+=work(l,mid)+work(mid+1,r); cc[0]=0;i=l;j=mid+1; while(i<=mid&&j<=r) { if (a2[i]<a2[j]) { cc[++cc[0]]=a2[i];++i; } else { cc[++cc[0]]=a2[j];++j; ans+=mid-i+1; } } for (;i<=mid;++i) cc[++cc[0]]=a2[i]; for (;j<=r;++j) cc[++cc[0]]=a2[j]; for (i=l;i<=r;++i) a2[i]=cc[i-l+1]; return ans; } void build(int &x,int l,int r) { int mid; tree[x=++tot].siz=0; if (l==r) return; mid=(l+r)/2; build(tree[x].l,l,mid); build(tree[x].r,mid+1,r); } void ins(int last,int &i,int l,int r,int x,int flag) { int mid; if (!i) i=++tot; tree[i].siz=tree[last].siz+flag; tree[i].l=tree[last].l;tree[i].r=tree[last].r; if (l==r) return; mid=(l+r)/2; if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag); else ins(tree[last].r,tree[i].r,mid+1,r,x,flag); } void bit_ins(int i,int x,int flag) { for (;i<=n;i+=lowbit(i)) ins(root[i],root[i],1,n,x,flag); } long long ask(int l,int r,int x,int flag) { long long ss=0; int mid,i; if (l==r) return 0; mid=(l+r)/2; if (flag==0) { ss=0; for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz; for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz; if (x<=mid) { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l; return ask(l,mid,x,flag); } else { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r; return ss+ask(mid+1,r,x,flag); } } else { ss=0; for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].r].siz; for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].r].siz; if (x<=mid) { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l; return ss+ask(l,mid,x,flag); } else { for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r; for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r; return ask(mid+1,r,x,flag); } } } long long bit_ask(int l,int r,int x,int flag) { q1[0]=q2[0]=0; for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l]; for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r]; return ask(1,n,x,flag); } int main() { freopen("inverse.in","r",stdin); freopen("inverse.out","w",stdout); int m,i,j,k; long long ans=0; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) { scanf("%d",&a[i]); num[a[i]]=i; } for (i=m;i>=1;--i) { scanf("%d",&del[i]); a[num[del[i]]]=0; } build(root[0],1,n); for (i=1;i<=n;++i) if (a[i]) { a2[++a2[0]]=a[i]; bit_ins(i,a[i],1); } ans=work(1,a2[0]); for (i=1;i<=m;++i) { k=del[i];j=num[k];a[j]=k; bit_ins(j,k,1); if (j>1) ans+=bit_ask(0,j-1,k,1); if (j<n) ans+=bit_ask(j,n,k,0); ansi[i]=ans; } for (i=m;i>=1;--i) printf("%lld\n",ansi[i]); fclose(stdin); fclose(stdout); }
其他树套树问题
cogs1345 K大数查询
题目大意:有n个连续的区间,每个区间可以放多个数,区间修改,查找区间内的第K大。
思路:树状数组(权值)套线段树(位置)。因为不会写其他的树套树,也不会树状数组的区间修改,于是只能写成这样了。插入的时候log^2n,查询的时候二分一下log^3n,然后就会发现自己T了。因为自己用了pushdown,然后就会开很多没有用的点,也会一遍一遍的访问他们。那我们只能不用pushdown,然后传入一个变量fadel,然后更新一下就可以了!!!那么这里的siz保存的就是这个节点及它下面的元素个数,并没有保存它上方的!!!因为这里是第K大,而我只会树状数组第K小,所以又用了一棵线段树来维护区间元素的个数,以转化成第K小。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct use{ int l,r,siz,del; }tree[20000000]={0}; int tot=0,wotr[200000]={0},delta[200000]={0},root[50001]={0},n,size=0; int lowbit(int x){return x&(-x);} void paint(int i,int x,int l,int r) { delta[i]+=x;wotr[i]+=x*(r-l+1); } void pushdown(int i,int l,int r) { int mid; mid=(l+r)/2; paint(i*2,delta[i],l,mid); paint(i*2+1,delta[i],mid+1,r); delta[i]=0; } void insert(int i,int l,int r,int ll,int rr) { int mid; if (ll<=l&&r<=rr) { paint(i,1,l,r); return; } mid=(l+r)/2; pushdown(i,l,r); if (ll<=mid) insert(i*2,l,mid,ll,rr); if (rr>mid) insert(i*2+1,mid+1,r,ll,rr); wotr[i]=wotr[i*2]+wotr[i*2+1]; } int work(int i,int l,int r,int ll,int rr) { int mid,sum=0; if (ll<=l&&r<=rr) return wotr[i]; pushdown(i,l,r);mid=(l+r)/2; if (ll<=mid) sum+=work(i*2,l,mid,ll,rr); if (rr>mid) sum+=work(i*2+1,mid+1,r,ll,rr); return sum; } void ins(int &i,int l,int r,int ll,int rr,int x,int fadel) { int mid; if (i==0) i=++tot; if (ll<=l&&r<=rr) { ++tree[i].del;tree[i].siz=(tree[i].l==0?0:tree[tree[i].l].siz)+(tree[i].r==0?0:tree[tree[i].r].siz)+tree[i].del*(r-l+1); return; } mid=(l+r)/2; if (ll<=mid) ins(tree[i].l,l,mid,ll,rr,x,fadel+tree[i].del); if (rr>mid) ins(tree[i].r,mid+1,r,ll,rr,x,fadel+tree[i].del); tree[i].siz=(tree[i].l==0?0:tree[tree[i].l].siz)+(tree[i].r==0?0:tree[tree[i].r].siz)+tree[i].del*(r-l+1); } void bit_ins(int x,int l,int r) { for (;x<=n;x+=lowbit(x)) ins(root[x],1,n,l,r,1,0); } int ask(int i,int l,int r,int ll,int rr,int fadel) { int mid,sum=0; if (!i) return (fadel*(min(r,rr)-max(l,ll)+1)); if (ll<=l&&r<=rr) return tree[i].siz+fadel*(r-l+1); mid=(l+r)/2; if (ll<=mid) sum+=ask(tree[i].l,l,mid,ll,rr,tree[i].del+fadel); if (rr>mid) sum+=ask(tree[i].r,mid+1,r,ll,rr,tree[i].del+fadel); return sum; } int bit_ask(int x,int ll,int rr) { int sum=0; for (;x>0;x-=lowbit(x)) sum+=ask(root[x],1,n,ll,rr,0); return sum; } int to_ask(int l,int r,int ll,int rr,int k) { int mid,sum=0,ans; if (l==r) return l; mid=(l+r)/2; sum=bit_ask(mid,ll,rr); if (k<=sum) ans=to_ask(l,mid,ll,rr,k); else ans=to_ask(mid+1,r,ll,rr,k); return ans; } int main() { freopen("zjoi13_sequence.in","r",stdin); freopen("zjoi13_sequence.out","w",stdout); int m,i,j,kind,aa,bb,cc; scanf("%d%d",&n,&m); for (i=1;i<=m;++i) { scanf("%d%d%d%d",&kind,&aa,&bb,&cc); if (kind==1) { bit_ins(cc,aa,bb); insert(1,1,n,aa,bb); } else { j=work(1,1,n,aa,bb); cc=j-cc+1; j=to_ask(1,n,aa,bb,cc); printf("%d\n",j); } } fclose(stdin); fclose(stdout); }