有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
输出每个询问的结果
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
分析:
还是一个整体二分的做法,对于区间更新,用树状数组或者线段树去维护
对于c可以全部+N+1转换成正数方便处理,负数在区间直接/2会出bug,在结果处将答案转换过来
另外就是要开long long
说实在的整体二分对手速的要求和仔细程度还真是高,毕竟是离线的不是很好找bug
#include<cstring> #include<cstdio> #include<algorithm> #include<iostream> using namespace std; #define maxn 50005 int n,m; long long ans[maxn]; struct node { int kind; int l,r; long long k; int index; } q[maxn],q1[maxn],q2[maxn]; long long c1[maxn],c2[maxn]; inline int lowbit(int x) { return x&-x; } inline void update(int x,long long val) { for(int i=x; i<=n; i+=lowbit(i)) { c1[i]+=val; c2[i]+=(x-1)*val; } } inline long long query(int x) { long long sum1=0,sum2=0; for(int i=x; i>0; i-=lowbit(i)) { sum1+=c1[i]; sum2+=c2[i]; } return sum1*x-sum2; } void divide(int s,int t,long long l,long long r) { if(s>t) return ; if(l==r) { for(int i=s; i<=t; i++) { if(q[i].kind==2) { ans[ q[i].index ]=l; } } return ; } long long mid=(l+r)/2; int num1=0,num2=0,flag1=0,flag2=0; for(int i=s; i<=t; i++) { if(q[i].kind==1) { if(q[i].k<=mid) { update(q[i].l,1); update(q[i].r+1,-1); q1[num1++]=q[i]; } else q2[num2++]=q[i]; } else { long long tmp=query(q[i].r)-query(q[i].l-1); if(tmp>=q[i].k) q1[num1++]=q[i],flag1=1; else q[i].k-=tmp,q2[num2++]=q[i],flag2=1; } } for(int i=s; i<=t; i++) { if(q[i].kind==1) { if(q[i].k<=mid) { update(q[i].l,-1); update(q[i].r+1,1); } } } for(int i=0; i<num1; i++) q[i+s]=q1[i]; for(int i=0; i<num2; i++) q[i+s+num1]=q2[i]; if(flag1) divide(s,s+num1-1,l,mid); if(flag2) divide(s+num1,t,mid+1,r); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { memset(c1,0,sizeof c1); memset(c2,0,sizeof c2); int num=0; for(int i=1; i<=m; i++) { scanf("%d%d%d%lld",&q[i].kind,&q[i].l,&q[i].r,&q[i].k); if(q[i].kind==1) { q[i].k+=n+1; q[i].k=2*n+2-q[i].k; } else if(q[i].kind==2) q[i].index=num++; } divide(1,m,1,2*n+2); for(int i=0; i<num; i++) { printf("%lld\n",(long long)n+1-ans[i]); } } return 0; }