题目
题解
题意大概是给你n个vector,对若干个编号连续的vector进行插入和查询。
典型的树套树呗
先对所有插入的c值建一棵线段树,然后每个节点再维护一棵线段树,叶子节点的线段树存该值在序列中的分布情况(也就是该值在序列中每个vector中的出现次数,维护区间和),父节点的线段树存限定区间内的所有c值在序列中的分布情况,也就是所有子节点的线段树合并。
插入就是对大线段树单点修改,对链上每个小线段树进行区间加;
查询就是利用大线段树进行二分答案,每次对小线段树进行区间查询,总复杂度。
树套树的码量名不虚传,好在我板子打得优美,少调试。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#define ll long long
#define MAXN 50005
#define MAXP 20000005
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n;
struct itn{ //小线段树
int ls,rs,lz;ll a;
itn(){ls=rs=lz=a=0;}
}t[MAXP];
int IN;
inline void pushd(int x,int l,int r){
if(t[x].lz>0){
if(l==r){t[x].lz=0;return;}
int mid=(l+r)>>1;
if(!t[x].ls)t[x].ls=++IN,t[IN]=itn();
t[t[x].ls].a+=(1ll+mid-l)*t[x].lz,t[t[x].ls].lz+=t[x].lz;
if(!t[x].rs)t[x].rs=++IN,t[IN]=itn();
t[t[x].rs].a+=(0ll+r-mid)*t[x].lz,t[t[x].rs].lz+=t[x].lz;
t[x].lz=0;
}
}
inline void addt(int x,int l,int r,int a,int b){
if(l==a&&r==b){
t[x].a+=r-l+1,t[x].lz++;
return;
}
int mid=(l+r)>>1;pushd(x,l,r);
if(a<=mid){
if(!t[x].ls)t[x].ls=++IN,t[IN]=itn();
addt(t[x].ls,l,mid,a,min(b,mid));
}
if(b>mid){
if(!t[x].rs)t[x].rs=++IN,t[IN]=itn();
addt(t[x].rs,mid+1,r,max(a,mid+1),b);
}
t[x].a=t[t[x].ls].a+t[t[x].rs].a;
}
inline ll sch(int x,int l,int r,int a,int b){
if(!x)return 0;
if(l==a&&r==b)return t[x].a;
int mid=(l+r)>>1;pushd(x,l,r);
ll res=0;
if(a<=mid)res+=sch(t[x].ls,l,mid,a,min(b,mid));
if(b>mid)res+=sch(t[x].rs,mid+1,r,max(a,mid+1),b);
return res;
}
struct ITN{ //大线段树
int ls,rs,id;
}tr[MAXN<<4];
int NN;
inline void add(int x,int l,int r,int a,int b,int z){
if(l==r){addt(tr[x].id,1,n,a,b);return;}
int mid=(l+r)>>1;
if(z<=mid){
if(!tr[x].ls)tr[x].ls=++NN,tr[tr[x].ls].id=++IN,t[IN]=itn();
add(tr[x].ls,l,mid,a,b,z);
}
else{
if(!tr[x].rs)tr[x].rs=++NN,tr[tr[x].rs].id=++IN,t[IN]=itn();
add(tr[x].rs,mid+1,r,a,b,z);
}
addt(tr[x].id,1,n,a,b);
}
inline int query(int x,int l,int r,int a,int b,ll c){
if(l==r)return l;
int mid=(l+r)>>1;ll z=sch(tr[tr[x].rs].id,1,n,a,b);
if(z>=c)return query(tr[x].rs,mid+1,r,a,b,c);
else return query(tr[x].ls,l,mid,a,b,c-z);
}
signed main()
{
n=read();
tr[++NN].id=++IN;
for(int M=read();M--;){
int opt=read(),a=read(),b=read();ll c=read();
if(opt==1)add(1,-n,n,a,b,c);
else printf("%d\n",query(1,-n,n,a,b,c));
}
return 0;
}