模板——数据结构

收集一些数据结构相关的模板/板题

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;
}
posted @ 2022-08-28 18:42  sz[sz]  阅读(36)  评论(0)    收藏  举报