模板——数据结构
收集一些数据结构相关的模板/板题
ST表
用pw数组存2的次幂,避免位运算优先级问题。
点击查看代码
int a[N],mx[N][M],pw[M],lg[N];
int cnt(int l,int r){
int p=lg[r-l+1];
return max(mx[l][p],mx[r-pw[p]+1][p]);
}
void work(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<M;i++) pw[i]=(1<<i);
lg[1]=0; for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=n;i;i--){
mx[i][0]=a[i];
for(int j=1;j<M && i+pw[j]-1<=n;j++) mx[i][j]=max(mx[i][j-1],mx[i+pw[j-1]][j-1]);
}
}
线段树
维护区间最值以及满足最值的个数
点击查看代码
//维护区间最值以及满足最值的个数
struct SGT{
int mx[N<<2],tg[N<<2],su[N<<2];
#define mid ((l+r)>>1)
#define lc (u<<1)
#define rc ((u<<1)|1)
void bld(int u,int l,int r){
mx[u]=tg[u]=su[u]=0;
if(l==r) return;
bld(lc,l,mid);
bld(rc,mid+1,r);
}
void pst(int u,int x){
mx[u]+=x;
tg[u]+=x;
}
void psd(int u){
if(!tg[u]) return;
pst(lc,tg[u]);
pst(rc,tg[u]);
tg[u]=0;
}
void psu(int u){
mx[u]=max(mx[lc],mx[rc]);
su[u]=0;
if(mx[lc]==mx[u]) Madd(su[u],su[lc]);
if(mx[rc]==mx[u]) Madd(su[u],su[rc]);
mx[u]+=tg[u];
}
void add(int u,int l,int r,int x,int y){
if(l==r){
Madd(su[u],y);
return;
}
psd(u);
if(x<=mid) add(lc,l,mid,x,y);
else add(rc,mid+1,r,x,y);
psu(u);
}
void upd(int u,int l,int r,int a,int b,int x){
if(a<=l && r<=b){
pst(u,x);
return;
}
psd(u);
if(a<=mid) upd(lc,l,mid,a,b,x);
if(b>mid) upd(rc,mid+1,r,a,b,x);
psu(u);
}
}T[2];
zkw线段树
void update(int l, int r, int d) {
for (l += N - 1, r += N + 1; l ^ r ^ 1; l >>= 1, r >>= 1)
{
if (l < N) tree[l] = max(tree[l << 1], tree[l << 1 | 1]) + mark[l],
tree[r] = max(tree[r << 1], tree[r << 1 | 1]) + mark[r];
if (~l & 1) tree[l ^ 1] += d, mark[l ^ 1] += d;
if (r & 1) tree[r ^ 1] += d, mark[r ^ 1] += d;
}
for (; l; l >>= 1, r >>= 1)
if (l < N) tree[l] = max(tree[l << 1], tree[l << 1 | 1]) + mark[l],
tree[r] = max(tree[r << 1], tree[r << 1 | 1]) + mark[r];
};
int query(int l, int r) {
int maxl = -INF, maxr = -INF;
for (l += N - 1, r += N + 1; l ^ r ^ 1; l >>= 1, r >>= 1)
{
maxl += mark[l], maxr += mark[r];
if (~l & 1) cmax(maxl, tree[l ^ 1]);
if (r & 1) cmax(maxr, tree[r ^ 1]);
}
for (; l; l >>= 1, r >>= 1)
maxl += mark[l], maxr += mark[r];
return max(maxl, maxr);
};
点分治
求点分树(ABC291Ex)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int hd[N],to[N<<1],nx[N<<1],tt;
inline void add(int u,int v){
nx[++tt]=hd[u];
to[hd[u]=tt]=v;
}
int n,rt,su,sz[N],mx[N];
bool vs[N];
void find(int u,int fa){
sz[u]=1; mx[u]=0;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
find(v,u);
sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
}
mx[u]=max(mx[u],su-sz[u]);
if(mx[u]<mx[rt]) rt=u;
//cout<<"find:"<<u<<" "<<sz[u]<<" "<<mx[u]<<" su="<<su<<endl;
}
void cnt_size(int u,int fa){
sz[u]=1; //mx[u]=0;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
cnt_size(v,u);
sz[u]+=sz[v];
//mx[u]=max(mx[u],sz[v]);
}
//mx[u]=max(mx[u],su-sz[u]);
//cout<<"cnt_size:"<<u<<" "<<sz[u]<<" "<<mx[u]<<endl;
}
int ans[N];
void dfz(int u,int fa){
vs[u]=1;
cnt_size(u,fa);
//cout<<"dfz:"<<u<<" "<<fa<<endl;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
su=sz[v]; rt=0;
find(v,u);
ans[rt]=u;
//cnt_size(rt,u);
//cout<<"v="<<v<<" "<<rt<<" "<<mx[v]<<" "<<sz[v]<<endl;
dfz(rt,u);
}
}
int main()
{
cin>>n;
for(int u,v,i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
su=n; rt=0; mx[0]=n;
find(1,0); //cnt_size(rt,0);
//cout<<"rt="<<rt<<endl;
ans[rt]=-1;
dfz(rt,0);
for(int i=1;i<=n;i++) printf("%d ",ans[i]); puts("");
return 0;
}
19ICPC HK C (子树容斥+二维偏序+卡常)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
//BIT
int tn;
int A[N];
inline void upd(int x,int y){
//printf("upd: x=%d y=%d\n",x,y);
while(x) A[x]+=y,x-=x&-x;//cout<<x<<endl;
}
inline int cnt(int x){
int s=0;
while(x<=tn) s+=A[x],x+=x&-x;//cout<<x<<endl;
return s;
}
//
typedef long long ll;
int dt[N];
inline void dsc(ll **h,int m){
for(int i=0;i<m;i++) dt[i]=*(h[i]);
sort(dt,dt+m);
for(int i=0;i<m;i++) *(h[i])=lower_bound(dt,dt+m,*(h[i]))-dt+1;
}
int hd[N],to[N<<1],nx[N<<1],tt;
inline void add(int u,int v){
nx[++tt]=hd[u];
to[hd[u]=tt]=v;
}
int n,a[N];
int rt,su,sz[N],mx[N];
bool vs[N];
void find(int u,int fa){
sz[u]=1; mx[u]=0;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
find(v,u);
sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
}
mx[u]=max(mx[u],su-sz[u]);
if(mx[u]<mx[rt]) rt=u;
//cout<<"find:"<<u<<" "<<sz[u]<<" "<<mx[u]<<" su="<<su<<endl;
}
void cnt_size(int u,int fa){
sz[u]=1; //mx[u]=0;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
cnt_size(v,u);
sz[u]+=sz[v];
//mx[u]=max(mx[u],sz[v]);
}
//mx[u]=max(mx[u],su-sz[u]);
//cout<<"cnt_size:"<<u<<" "<<sz[u]<<" "<<mx[u]<<endl;
}
struct node{
ll sm,mx,u,v;
}p[N];
ll ans;
bool cmp(node u,node v){
return u.mx<v.mx;
}
int aw,ct;
node h[N];
void dfs(int u,int fa){
h[ct++]=p[u];
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
p[v]=(node){p[u].sm+a[v],max(p[u].mx,1ll*a[v]),0,0};
dfs(v,u);
}
}
inline void cal(node *h,int m,int op){
//if(n==69369) return;
sort(h,h+m,cmp);
ll** tmp=new ll*[m+m];
//cout<<"cal: op="<<op<<endl;
for(int i=0;i<m;i++){
h[i].u=h[i].mx*2-h[i].sm;
h[i].v=h[i].sm-aw;
tmp[i+i]=(ll*)(&h[i])+2;
tmp[i+i+1]=(ll*)(&h[i])+3;
//cout<<h[i].mx<<" "<<h[i].sm<<endl;
}
dsc(tmp,m+m);
tn=m+m;
for(int i=0;i<m;i++){
ans+=op*cnt(h[i].u);
upd(h[i].v-1,1);
}
for(int i=1;i<=tn;i++) A[i]=0;
//cout<<"ans="<<ans<<endl;
//for(int i=0;i<m;i++) delete[] tmp[i];
delete[] tmp;
}
node g[N];
void cnt_ans(int u,int fa){
//cout<<"cnt_ans: u="<<u<<endl;
aw=a[u];
p[u].sm=p[u].mx=a[u];
//int tot=0;
int ut=0;
g[ut++]=p[u];
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
p[v]=(node){a[u]+a[v],max(a[u],a[v]),0,0};
ct=0;
dfs(v,u);
cal(h,sz[v],-1);
for(int i=0;i<sz[v];i++) g[ut++]=h[i];
}
//sum+=g.size();
cal(g,sz[u],1);
}
void dfz(int u,int fa){
vs[u]=1;
cnt_size(u,fa);
cnt_ans(u,fa);
//cout<<"dfz:"<<u<<" "<<fa<<endl;
for(int e=hd[u];e;e=nx[e]) if(to[e]!=fa && !vs[to[e]]){
int v=to[e];
su=sz[v]; rt=0;
find(v,u);
//cnt_size(rt,u);
//cout<<"v="<<v<<" "<<rt<<" "<<mx[v]<<" "<<sz[v]<<endl;
dfz(rt,u);
}
}
void work(){
cin>>n; ans=tt=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),hd[i]=vs[i]=0;
for(int u,v,i=1;i<n;i++){
scanf("%d%d",&u,&v),add(u,v),add(v,u);
}
su=n; rt=0;
find(1,0); //cnt_size(rt,0);
dfz(rt,0);
cout<<ans<<endl;
}
int main()
{
mx[0]=N;
int T; cin>>T; for(int i=1;i<=T;i++) work();
return 0;
}
cdq分治(优化dp+二维偏序+预处理归并排序)
预处理归并排序的易错点
for(int i=l,u=l,v=mid+1;i<=r;i++){
if( v>r || (u<=mid && A[d+1][u].a<A[d+1][v].a) ) A[d][i]=A[d+1][u++];
// "u<=mid" is necessary!!
else A[d][i]=A[d+1][v++];
}
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n; ll v0;
struct node{
ll a,t,u,v;
int d;
}p[N],A[20][N];
struct BIT{
int n;
int* a;
BIT(int m){
n=m;
a=new int[m+1];
for(int i=1;i<=n;i++) a[i]=-N;
}
void upd(int x,int y){
while(x<=n) a[x]=max(a[x],y),x+=x&-x;
}
int cnt(int x){
int mx=-N;
while(x) mx=max(mx,a[x]),x-=x&-x;
return mx;
}
};
void pre(int l,int r,int d){
if(l==r){
A[d][l]=p[l];
return;
}
int mid=((l+r)>>1);
pre(l,mid,d+1); pre(mid+1,r,d+1);
for(int i=l,u=l,v=mid+1;i<=r;i++){
if( v>r || (u<=mid && A[d+1][u].a<A[d+1][v].a) ) A[d][i]=A[d+1][u++];
// "u<=mid" is necessary!!
else A[d][i]=A[d+1][v++];
}
}
int f[N];
ll pu[N],pv[N];
void solve(int l,int r,int d){
if(l==r) return;
int mid=((l+r)>>1),len=r-l+1;
solve(l,mid,d+1);
//init
for(int i=l;i<=r;i++){
A[d+1][i].u=v0*A[d+1][i].t-A[d+1][i].a;
A[d+1][i].v=v0*A[d+1][i].t+A[d+1][i].a;
pu[i-l+1]=A[d+1][i].u;
pv[i-l+1]=A[d+1][i].v;
}
sort(pu+1,pu+len+1);
sort(pv+1,pv+len+1);
for(int i=l;i<=r;i++){
A[d+1][i].u=lower_bound(pu+1,pu+len+1,A[d+1][i].u)-pu;
A[d+1][i].v=lower_bound(pv+1,pv+len+1,A[d+1][i].v)-pv;
}
//cnt
BIT T(len);
for(int i=mid+1,j=l;i<=r;i++){
while(j<=mid && A[d+1][j].a<=A[d+1][i].a){
T.upd(A[d+1][j].u,f[A[d+1][j].d]);
j++;
}
f[A[d+1][i].d]=max(f[A[d+1][i].d],1+T.cnt(A[d+1][i].u));
}
BIT Q(len);
for(int i=r,j=mid;i>mid;i--){
while(j>=l && A[d+1][j].a>=A[d+1][i].a){
Q.upd(A[d+1][j].v,f[A[d+1][j].d]);
j--;
}
f[A[d+1][i].d]=max(f[A[d+1][i].d],1+Q.cnt(A[d+1][i].v));
}
solve(mid+1,r,d+1);
}
int main()
{
cin>>n>>v0;
for(int i=1;i<=n;i++) scanf("%lld",&p[i].t),p[i].d=i;
for(int i=1;i<=n;i++) scanf("%lld",&p[i].a),f[i]=-N;
p[0].d=p[0].a=p[0].t=0;
pre(0,n,0);
solve(0,n,0);
int ans=-N;
for(int i=0;i<=n;i++) ans=max(ans,f[i]);
cout<<ans<<endl;
return 0;
}
二维矩形交计算贡献
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
struct BIT{
int n;
ll s[N];
BIT(int m){
n=m+1;
for(int i=1;i<=n;i++) s[i]=0;
}
void add(int x,ll y){
x++;
while(x<=n) s[x]+=y,x+=x&-x;
}
ll cnt(int x){
x++;
ll su=0;
while(x) su+=s[x],x-=x&-x;
return su;
}
};
struct qry{
ll x,y;
int d,p;
bool operator < (const qry& u) const {
return y<u.y;
}
}q[N<<2];
struct opr{
ll x,y,w;
bool operator < (const opr& u) const {
return y<u.y;
}
}p[N<<2];
int n,m,qt,pt;
ll ans[N];
void add(qry& u,ll x){
if(u.p==1) ans[u.d]+=x;
else ans[u.d]-=x;
}
void cnt(){
sort(q+1,q+qt+1); sort(p+1,p+pt+1);
BIT r1(n),r2(n);
BIT l1(n),l2(n);
ll sw=0,sm=0;
for(int i=1;i<=pt;i++){
r1.add(p[i].x,p[i].w);
r2.add(p[i].x,p[i].x*p[i].w);
sw+=p[i].w;
}
for(int i=1,j=1;i<=qt;i++){
while(j<=pt && p[j].y<=q[i].y){
//!!p[j].y<=q[i].y
opr u=p[j];
int d=u.x;
r1.add(d,-u.w),r2.add(d,-u.w*u.x);
l1.add(d,u.y*u.w),l2.add(d,u.y*u.x*u.w);
sm+=u.y*u.w;
sw-=u.w;
j++;
}
qry& v=q[i];
int x=v.x;
add(v,l2.cnt(x));
add(v,q[i].x*(sm-l1.cnt(x)));
add(v,q[i].y*(r2.cnt(x)));
add(v,q[i].y*q[i].x*(sw-r1.cnt(x)));
}
}
1.转化为矩形交的贡献CF1824D
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
struct BIT{
int n;
ll s[N];
BIT(int m){
n=m+1;
for(int i=1;i<=n;i++) s[i]=0;
}
void add(int x,ll y){
x++;
while(x<=n) s[x]+=y,x+=x&-x;
}
ll cnt(int x){
x++;
ll su=0;
while(x) su+=s[x],x-=x&-x;
return su;
}
};
struct qry{
ll x,y;
int d,p;
bool operator < (const qry& u) const {
return y<u.y;
}
}q[N<<2];
struct opr{
ll x,y,w;
bool operator < (const opr& u) const {
return y<u.y;
}
}p[N<<2];
int n,m,qt,pt;
void ins(int t,int l,int r,int x){
p[++pt]=(opr){t,r,x};
p[++pt]=(opr){t,l-1,-x};
}
int a[N],last[N];
struct node{
int l,r,x;
};
void init(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
last[i]=n+1;
}
stack<node>sta;
for(int i=n;i;i--){
int r=last[a[i]]-1;
last[a[i]]=i;
while(!sta.empty() && r>=sta.top().l){
node u=sta.top();
sta.pop();
ins(i,u.l,min(r,u.r),-u.x);
if(r<u.r) sta.push((node){r+1,u.r,u.x});
if(r<=u.r) break;
}
ins(i,i,r,i);
sta.push((node){i,r,i});
}
for(int i=1;i<=m;i++){
int l,r,x,y;
scanf("%d%d%d%d",&l,&r,&x,&y);
q[++qt]=(qry){r,y,i,1};
q[++qt]=(qry){r,x-1,i,-1};
q[++qt]=(qry){l-1,y,i,-1};
q[++qt]=(qry){l-1,x-1,i,1};
}
}
ll ans[N];
void add(qry& u,ll x){
if(u.p==1) ans[u.d]+=x;
else ans[u.d]-=x;
}
void cnt(){
sort(q+1,q+qt+1); sort(p+1,p+pt+1);
BIT r1(n),r2(n);
BIT l1(n),l2(n);
ll sw=0,sm=0;
for(int i=1;i<=pt;i++){
r1.add(p[i].x,p[i].w);
r2.add(p[i].x,p[i].x*p[i].w);
sw+=p[i].w;
}
for(int i=1,j=1;i<=qt;i++){
while(j<=pt && p[j].y<=q[i].y){
//!!p[j].y<=q[i].y
opr u=p[j];
int d=u.x;
r1.add(d,-u.w),r2.add(d,-u.w*u.x);
l1.add(d,u.y*u.w),l2.add(d,u.y*u.x*u.w);
sm+=u.y*u.w;
sw-=u.w;
j++;
}
qry& v=q[i];
int x=v.x;
add(v,l2.cnt(x));
add(v,q[i].x*(sm-l1.cnt(x)));
add(v,q[i].y*(r2.cnt(x)));
add(v,q[i].y*q[i].x*(sw-r1.cnt(x)));
}
}
int main(){
init();
cnt();
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}
2.二维偏序经典模板CCPC2022广州B
区间容斥+矩形交+自然溢出
预处理时,把贡献位置、横纵坐标考虑清楚!!
计算答案时,把如何处理unsigned、每个部分如何算贡献想清楚!!
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int ll
typedef long long ll;
typedef unsigned long long ul;
const int N=1e6+5,P=1e9+7;
struct BIT{
int n;
ul s[N];
BIT(int m){
n=m+1;
for(int i=1;i<=n;i++) s[i]=0;
return;
}
void add(int x,ul y){
x++;
while(x<=n) s[x]+=y,x+=x&-x;
}
ul cnt(int x){
x++;
ul su=0;
while(x) su+=s[x],x-=x&-x;
return su;
}
};
struct node{
int l,r,w;
bool operator < (const node& u) const{
return l<u.l;
}
};
struct qry{
ul x,y;
int d,p;
bool operator < (const qry& u) const {
return y<u.y;
}
}q[N<<3];
struct opr{
ul x,y;
int p;
ul w;
bool operator < (const opr& u) const {
return y<u.y;
}
}p[N];
int n,m,qt,pt;
set<node>st;
void ins(int i,node u){
st.insert(u);
q[++qt]=(qry){u.l-1,m-i+1,u.w,-1};
q[++qt]=(qry){u.r,m-i+1,u.w,1};
}
void del(int i,set<node>:: iterator ut){
node u=*ut;
q[++qt]=(qry){u.l-1,m-i+1,u.w,1};
q[++qt]=(qry){u.r,m-i+1,u.w,-1};
st.erase(ut);
}
void init(){
cin>>n>>m;
for(int i=1,x;i<=n;i++){
scanf("%lld",&x);
ins(1,(node){i,i,x});
}
for(int i=1;i<=m;i++){
int op,l,r,w;
scanf("%lld%lld%lld%lld",&op,&l,&r,&w);
if(op==1){
set<node>:: iterator it=st.upper_bound((node){l,0,0});
it--;
set<node>:: iterator jt=st.upper_bound((node){r,0,0});
jt--;
node tu=*it,tv=*jt;
int L=(it->l),R=(jt->r);
vector<set<node>:: iterator>tmp;
while(1){
tmp.push_back(it);
if(it==jt) break;
it++;
}
for(int j=0;j<(int)tmp.size();j++) del(i,tmp[j]);
if(L<l) tu.r=l-1,ins(i,tu);
if(r<R) tv.l=r+1,ins(i,tv);
ins(i,(node){l,r,w});
}
else{
p[++pt]=(opr){l-1,m-i+1,-1,w};
p[++pt]=(opr){r,m-i+1,1,w};
}
}
}
ul ans[N];
void add(qry& u,ul x){
if(u.p==1) ans[u.d]+=x;
else ans[u.d]-=x;
}
bool cmp(qry u,qry v){
return u.d<v.d;
}
void cnt(){
sort(q+1,q+qt+1); sort(p+1,p+pt+1);
BIT r1(n),r2(n);
BIT l1(n),l2(n);
ul sw=0,sm=0;
for(int i=1;i<=pt;i++){
if(p[i].p==-1) p[i].w=-p[i].w;
r1.add(p[i].x,p[i].w);
r2.add(p[i].x,p[i].x*p[i].w);
sw+=p[i].w;
}
for(int i=1,j=1;i<=qt;i++){
while(j<=pt && p[j].y<=q[i].y){
//!!p[j].y<=q[i].y
opr u=p[j];
int d=u.x;
r1.add(d,-u.w),r2.add(d,-u.w*u.x);
l1.add(d,u.y*u.w),l2.add(d,u.y*u.x*u.w);
sm+=u.y*u.w;
sw-=u.w;
j++;
}
qry& v=q[i];
int x=v.x;
add(v,l2.cnt(x));
add(v,q[i].x*(sm-l1.cnt(x)));
add(v,q[i].y*(r2.cnt(x)));
add(v,q[i].y*q[i].x*(sw-r1.cnt(x)));
}
}
signed main(){
init();
cnt();
for(int i=1;i<=n;i++) printf("%llu ",ans[i]); puts("");
return 0;
}
分块+线段树二分
分块存散点的数组要记得开两倍!!
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int N=1e5+5,M=2005,T=N*62,F=2e9;
int n,m,q,a[N];
int B,K,L[M],R[M],id[N],rt[M],tt;
int lc[T],rc[T],cu[T];
ll su[T];
int res[M],blk[M],tr,tb;
ll rsu[M];
#define mid ((l+r)>>1)
void upd(int& u,int l,int r,int x,int y){
if(!u) u=++tt;
cu[u]+=y;
su[u]+=1ll*x*y;
//cout<<l<<" "<<r<<endl;
if(l==r) return;
if(x<=mid) upd(lc[u],l,mid,x,y);
else upd(rc[u],mid+1,r,x,y);
}
bool chk(int x,int k,ll c0,ll s0){
//cout<<"x="<<x<<" k="<<k<<" len="<<len<<endl;
ll c=c0,s=s0;
res[tr]=F;
int t=lower_bound(res,res+tr+1,x)-res;
//cout<<"t="<<t<<endl;
c+=t;
if(t) s+=rsu[t-1];
for(int i=0;i<tb;i++) c+=cu[lc[blk[i]]],s+=su[lc[blk[i]]];
//cout<<"c="<<c<<" s="<<s<<endl;
return c*x-s<=1ll*k*x;
}
ll qry(int l,int r,int k,ll c0,ll s0){
if(l==r){
return l;
}
if(chk(mid+1,k,c0,s0)){
for(int i=0;i<tb;i++) c0+=cu[lc[blk[i]]],s0+=su[lc[blk[i]]],blk[i]=rc[blk[i]];
return qry(mid+1,r,k,c0,s0);
}
else{
for(int i=0;i<tb;i++) blk[i]=lc[blk[i]];
return qry(l,mid,k,c0,s0);
}
}
signed main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]=m-1-a[i];
B=(int)sqrt(n*3);
//B=n;
K=(n-1)/B+1;
for(int i=1;i<=K;i++){
L[i]=R[i-1]+1;
R[i]=min(n,R[i-1]+B);
//printf("l=%d r=%d\n",L[i],R[i]);
for(int j=L[i];j<=R[i];j++) id[j]=i,upd(rt[i],0,m-1,a[j],1);
//rt[i]=++tt;
}
//return 0;
while(q--){
int op,l,r,k,u,v;
scanf("%lld",&op);
if(op==1){
scanf("%lld%lld%lld",&l,&r,&k);
u=id[l],v=id[r];
//rest
tr=0;
//!!! consider each opt of res to rsu
if(u==v){
for(int i=l;i<=r;i++) res[tr++]=a[i];
}
else{
for(int i=l;i<=R[u];i++) res[tr++]=a[i];
for(int i=L[v];i<=r;i++) res[tr++]=a[i];
}
sort(res,res+tr);
rsu[0]=res[0];
//cout<<rsu[0]<<" ";
for(int i=1;i<tr;i++) rsu[i]=rsu[i-1]+res[i];//cout<<rsu[i]<<" ";
//puts("");
//block
tb=0;
for(int i=u+1;i<v;i++) blk[tb++]=rt[i];
//cnt
ll ans=qry(0,m-1,k,0,0);
if(ans==m-1){
ll s=rsu[tr-1];
for(int i=u+1;i<v;i++) s+=su[rt[i]];
ans=s/(r-l+1-k);
}
printf("%lld\n",ans);
}
else{
scanf("%lld%lld",&u,&v);
v=m-1-v;
upd(rt[id[u]],0,m-1,a[u],-1);
a[u]=v;
upd(rt[id[u]],0,m-1,a[u],1);
}
}
return 0;
}
浙公网安备 33010602011771号