https://www.luogu.org/problemnew/show/P3332
题目描述
有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<=long long
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,tot; 4 int ans[100050]; 5 struct node 6 { 7 int opt,l,r,pos; 8 long long val; 9 }num[100050],tl[100050],tr[100050]; 10 long long c1[50050],c2[50050]; 11 void add(int u,int v) 12 { 13 for(int i=u;i<=n;i+=i&-i) 14 c1[i]+=v,c2[i]+=v*u; 15 } 16 long long ask(int u) 17 { 18 long long tmp=0; 19 for(int i=u;i;i-=i&-i) 20 tmp+=(u+1)*c1[i]-c2[i]; 21 return tmp; 22 } 23 void calc_add(int l,int r,int v) 24 { 25 add(l,v); add(r+1,-v); 26 } 27 long long calc_ask(int l,int r) 28 { 29 return ask(r)-ask(l-1); 30 } 31 void calc(int L,int R,int l,int r) 32 { 33 if(l==r) 34 { 35 for(int i=L;i<=R;++i) ans[num[i].pos]=l; 36 return ; 37 } 38 int mid=(l+r)>>1; 39 bool fl=0,fr=0; 40 int topl=0,topr=0; 41 for(int i=L;i<=R;++i) 42 if(num[i].opt==1) 43 { 44 if(num[i].val<=mid) 45 tl[++topl]=num[i]; 46 else 47 { 48 calc_add(num[i].l,num[i].r,1); 49 tr[++topr]=num[i]; 50 } 51 } 52 else 53 { 54 long long tmp=calc_ask(num[i].l,num[i].r); 55 if(num[i].val>tmp) 56 { 57 num[i].val-=tmp; 58 fl=true; 59 tl[++topl]=num[i]; 60 } 61 else 62 { 63 fr=true; 64 tr[++topr]=num[i]; 65 } 66 } 67 for(int i=L;i<=R;++i) 68 if(num[i].opt==1&&num[i].val>mid) 69 calc_add(num[i].l,num[i].r,-1); 70 for(int i=1;i<=topl;++i) num[L+i-1]=tl[i]; 71 for(int i=1;i<=topr;++i) num[L+topl+i-1]=tr[i]; 72 if(fl) calc(L,L+topl-1,l,mid); 73 if(fr) calc(L+topl,R,mid+1,r); 74 } 75 int main() 76 { 77 scanf("%d%d",&n,&m); 78 for(int i=1;i<=m;++i) 79 { 80 scanf("%d%d%d%lld",&num[i].opt,&num[i].l,&num[i].r,&num[i].val); 81 if(num[i].opt==2) num[i].pos=++tot; 82 } 83 calc(1,m,-n,n); 84 for(int i=1;i<=tot;++i) printf("%d\n",ans[i]); 85 return 0; 86 }