BZOJ1901: Zju2112 Dynamic Rankings
题解: 一般来说 一眼带修主席树...主席树+树状数组 2个log常规操作 刚开了整体二分 发现整体二分也是很顺手的 整体二分思想不复杂 类似于cdq那样分治离线考虑贡献 因为这题设计到修改操作 所以我们可以将修改拆成删去和加入元素即可 用两个树状数组维护答案即可
树套树版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /************************************************************** Problem: 1901 User: c20161007 Language: C++ Result: Accepted Time:384 ms Memory:48896 kb ****************************************************************/ #include <bits/stdc++.h> const int MAXN=2e4+10; using namespace std; int read(){ int x=0,f=1; char ch= getchar (); while (! isdigit (ch)){ if (ch== '-' )f=-1;ch= getchar ();} while ( isdigit (ch))x=x*10+ch- '0' ,ch= getchar (); return f*x; } typedef struct node{ int l,r,sum; }node; node d[MAXN*201]; int rt[MAXN]; int cnt; int get_id( int x){ return x&(-x);} void update( int &x, int y, int l, int r, int t, int vul){ x=++cnt;d[x]=d[y];d[x].sum+=vul; if (l==r) return ; int mid=(l+r)>>1; if (t<=mid)update(d[x].l,d[y].l,l,mid,t,vul); else update(d[x].r,d[y].r,mid+1,r,t,vul); } int ans,sum; vector< int >v1; vector< int >v2; void querty( int l, int r, int k){ if (l==r){ans=l; return ;} sum=0; int mid=(l+r)>>1; for ( int i=0;i<v1.size();i++)sum+=d[d[v1[i]].l].sum; for ( int i=0;i<v2.size();i++)sum-=d[d[v2[i]].l].sum; // cout<<l<<" "<<r<<" "<<sum<<endl; if (k<=sum){ for ( int i=0;i<v1.size();i++)v1[i]=d[v1[i]].l; for ( int i=0;i<v2.size();i++)v2[i]=d[v2[i]].l; querty(l,mid,k); } else { for ( int i=0;i<v1.size();i++)v1[i]=d[v1[i]].r; for ( int i=0;i<v2.size();i++)v2[i]=d[v2[i]].r; querty(mid+1,r,k-sum); } } vector< int >vec; int a[MAXN]; typedef struct Q{ int op,l,r,k; }Q; Q q[MAXN]; int main(){ int n,m;n=read();m=read(); for ( int i=1;i<=n;i++)a[i]=read(),vec.push_back(a[i]); char ch; for ( int i=1;i<=m;i++){ scanf ( " %c" ,&ch); if (ch== 'Q' ){q[i].op=1;q[i].l=read();q[i].r=read();q[i].k=read();} else {q[i].op=2;q[i].l=read();q[i].r=read();vec.push_back(q[i].r);} } sort(vec.begin(),vec.end()); int sz=unique(vec.begin(),vec.end())-vec.begin(); for ( int i=1;i<=n;i++){ a[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1; // cout<<a[i]<<" "; for ( int j=i;j<=n;j+=get_id(j))update(rt[j],rt[j],1,sz,a[i],1); // cout<<endl; } // cout<<endl; for ( int i=1;i<=m;i++){ if (q[i].op==2){ q[i].r=lower_bound(vec.begin(),vec.begin()+sz,q[i].r)-vec.begin()+1; for ( int j=q[i].l;j<=n;j+=get_id(j))update(rt[j],rt[j],1,sz,a[q[i].l],-1),update(rt[j],rt[j],1,sz,q[i].r,1); a[q[i].l]=q[i].r; } else { v1.clear();v2.clear(); // cout<<q[i].l<<" "<<q[i].r<<" "<<q[i].k<<endl; for ( int j=q[i].r;j>0;j-=get_id(j))v1.push_back(rt[j]); // cout<<endl; for ( int j=q[i].l-1;j>0;j-=get_id(j))v2.push_back(rt[j]); // cout<<endl; querty(1,sz,q[i].k); printf ( "%d\n" ,vec[ans-1]); } } return 0; } |
整体二分版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | /************************************************************** Problem: 1901 User: c20161007 Language: C++ Result: Accepted Time:292 ms Memory:2112 kb ****************************************************************/ #include <bits/stdc++.h> const int MAXN=1e4+10; const int inf=1e9; using namespace std; int n,m; int b[MAXN],id[MAXN<<1]; typedef struct node{ int l,r,k,ans,cnt; }node; node que[MAXN<<1]; typedef struct Node{ int pos,vul; friend bool operator<(Node aa,Node bb){ return aa.vul<bb.vul;} }Node; Node a[MAXN]; int get_id( int x){ return x&(-x);} int sum[MAXN]; void update( int x, int vul){ for ( int i=x;i<=n;i+=get_id(i))sum[i]+=vul; } int Sum( int x){ int sum1=0; for ( int i=x;i>0;i-=get_id(i))sum1+=sum[i]; return sum1; } int num[MAXN]; void update1( int x, int vul){ for ( int i=x;i<=n;i+=get_id(i))num[i]+=vul; } int Sum1( int x){ int sum1=0; for ( int i=x;i>0;i-=get_id(i))sum1+=num[i]; return sum1; } int querty( int t){ return Sum(que[t].r)-Sum(que[t].l-1);} int querty1( int t){ return Sum1(que[t].r)-Sum1(que[t].l-1);} int tot; int ed[MAXN<<1],ip[MAXN<<1]; void slove( int ql, int qr, int l, int r){ if (ql>qr||l==r) return ; //cout<<l<<" "<<r<<endl; int mid=(l+r)>>1; int cnt=0,cnt1=0; while (tot<n&&a[tot+1].vul<=mid){ tot++; update(a[tot].pos,1); } while (tot&&a[tot].vul>mid){ update(a[tot].pos,-1); tot--; } //cout<<tot<<" "<<mid<<endl; for ( int i=ql;i<=qr;i++){ //cout<<que[id[i]].l<<":::::"<<que[id[i]].r<<" "<<que[id[i]].ans<<endl; if (que[id[i]].k==0){ if (que[id[i]].ans<=mid)update1(que[id[i]].l,que[id[i]].r); if (que[id[i]].ans<=mid)ed[++cnt]=id[i]; else ip[++cnt1]=id[i]; } else { //cout<<que[id[i]].l<<"==="<<que[id[i]].r<<" "<<querty(id[i])<<endl; if (querty(id[i])+que[id[i]].cnt+querty1(id[i])>=que[id[i]].k)ed[++cnt]=id[i],que[id[i]].ans=mid; else ip[++cnt1]=id[i],que[id[i]].cnt+=querty1(id[i]); } } for ( int i=ql;i<=qr;i++) if (que[id[i]].k==0&&que[id[i]].ans<=mid)update1(que[id[i]].l,-1*que[id[i]].r); for ( int i=1;i<=cnt;i++)id[ql+i-1]=ed[i]; for ( int i=1;i<=cnt1;i++)id[ql+cnt+i-1]=ip[i]; slove(ql,ql+cnt-1,l,mid); slove(ql+cnt,qr,mid+1,r); } int main(){ scanf ( "%d%d" ,&n,&m);tot=0; for ( int i=1;i<=n;i++) scanf ( "%d" ,&b[i]),a[i]=(Node){i,b[i]}; int l,r,k; char ch; int cnt=0; for ( int i=1;i<=m;i++){ scanf ( " %c" ,&ch); scanf ( "%d%d" ,&l,&r); if (ch== 'Q' ) scanf ( "%d" ,&k),que[++cnt]=(node){l,r,k,0},id[cnt]=cnt; else que[++cnt]=(node){l,-1,0,b[l]},id[cnt]=cnt,que[++cnt]=(node){l,1,0,r},b[l]=r,id[cnt]=cnt; } sort(a+1,a+n+1); slove(1,cnt,0,inf); for ( int i=1;i<=cnt;i++) if (que[i].k!=0) printf ( "%d\n" ,que[i].ans); return 0; } |
1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 9144 Solved: 3828
[Submit][Status][Discuss]
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1
],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改
变后的a继续回答上面的问题。
Input
第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。
分别表示序列的长度和指令的个数。
第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。
接下来的m行描述每条指令
每行的格式是下面两种格式中的一种。
Q i j k 或者 C i t
Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)
表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t
m,n≤10000
Output
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Sample Input
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
6
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)