P3332 [ZJOI2013]K大数查询

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

 

输出格式:

 

输出每个询问的结果

 

输入输出样例

输入样例
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
输出样例
1
2
1

说明

样例说明

第一个操作后位置 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

  

 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 }
View Code

 

posted @ 2019-02-11 17:06  Hevix  阅读(111)  评论(0编辑  收藏  举报