1. 程式人生 > >BZOJ 3110 [Zjoi2013]K大數查詢(整體二分)

BZOJ 3110 [Zjoi2013]K大數查詢(整體二分)

題解 gre void 有關 pre \n str k大數查詢 如果

3110: [Zjoi2013]K大數查詢

Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 11654 Solved: 3505
[Submit][Status][Discuss]

Description

有N個位置,M個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入一個數c
如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第C大的數是多少。

Input

第一行N,M
接下來M行,每行形如1 a b c或2 a b c

Output

輸出每個詢問的結果

Sample Input

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

Sample Output

1
2
1

HINT



【樣例說明】

第一個操作 後位置 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

題解

求第K大。

然後我們把權值設為n-c+1;

最後答案為n-ans+1就把問題轉化為了第k小

不過這題是插入。其實不是很難畢竟只是把權值小於mid的數的位置都加一就行了,我們把修改二分和一個位置多少個權值沒有關系。

和以前唯一的區別就是這次是整體修改,用線段樹就行了(就是慢)

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace
std; 7 const long long N=100010; 8 struct query{ 9 long long type,x,y,w,id; 10 }q[N],c2[N],c1[N]; 11 long long ans[N],m,n,tot; 12 struct tree{ 13 long long l,r,lazy,sum; 14 }tr[N*5]; 15 void update(long long now){ 16 tr[now].sum=tr[now*2].sum+tr[now*2+1].sum; 17 } 18 void pushdown(long long now){ 19 if(tr[now].lazy==0)return; 20 tr[now*2].sum+=(tr[now*2].r-tr[now*2].l+1)*tr[now].lazy; 21 tr[now*2+1].sum+=(tr[now*2+1].r-tr[now*2+1].l+1)*tr[now].lazy; 22 tr[now*2].lazy+=tr[now].lazy; 23 tr[now*2+1].lazy+=tr[now].lazy; 24 tr[now].lazy=0; 25 } 26 void build(long long l,long long r,long long now){ 27 tr[now].l=l;tr[now].r=r; 28 if(l==r)return; 29 long long mid=(l+r)>>1; 30 build(l,mid,now*2); 31 build(mid+1,r,now*2+1); 32 } 33 void add(long long l,long long r,long long c,long long now){ 34 pushdown(now); 35 if(tr[now].l==l&&tr[now].r==r){ 36 tr[now].sum+=(tr[now].r-tr[now].l+1)*c; 37 tr[now].lazy+=c; 38 return; 39 } 40 long long mid=(tr[now].l+tr[now].r)>>1; 41 if(l>mid)add(l,r,c,now*2+1); 42 else if(r<=mid)add(l,r,c,now*2); 43 else{ 44 add(l,mid,c,now*2); 45 add(mid+1,r,c,now*2+1); 46 } 47 update(now); 48 } 49 long long check(long long l,long long r,long long now){ 50 pushdown(now); 51 if(tr[now].l==l&&tr[now].r==r){ 52 return tr[now].sum; 53 } 54 long long mid=(tr[now].l+tr[now].r)>>1; 55 if(l>mid)return check(l,r,now*2+1); 56 else if(r<=mid)return check(l,r,now*2); 57 else return check(l,mid,now*2)+check(mid+1,r,now*2+1); 58 } 59 void solve(long long l,long long r,long long L,long long R){ 60 if(l>r)return ; 61 if(L==R){ 62 for(long long i=l;i<=r;i++){ 63 if(q[i].type==2)ans[q[i].id]=L; 64 } 65 return; 66 } 67 long long mid=(L+R)>>1; 68 long long lnow=0;long long rnow=0; 69 for(long long i=l;i<=r;i++){ 70 if(q[i].type==1){ 71 if(q[i].w<=mid){ 72 add(q[i].x,q[i].y,1,1); 73 c1[++lnow]=q[i]; 74 } 75 else c2[++rnow]=q[i]; 76 } 77 else{ 78 long long tmp=check(q[i].x,q[i].y,1); 79 if(tmp>=q[i].w)c1[++lnow]=q[i]; 80 else{ 81 q[i].w-=tmp; 82 c2[++rnow]=q[i]; 83 } 84 } 85 } 86 for(long long i=1;i<=lnow;i++){ 87 if(c1[i].type==1)add(c1[i].x,c1[i].y,-1,1); 88 } 89 for(long long i=1;i<=lnow;i++){ 90 q[l+i-1]=c1[i]; 91 } 92 for(long long i=1;i<=rnow;i++){ 93 q[l+lnow+i-1]=c2[i]; 94 } 95 solve(l,l+lnow-1,L,mid); 96 solve(l+lnow,r,mid+1,R); 97 } 98 int main(){ 99 scanf("%lld%lld",&n,&m); 100 build(1,n,1); 101 for(long long i=1;i<=m;i++){ 102 long long k,a,b,c; 103 scanf("%lld%lld%lld%lld",&k,&a,&b,&c); 104 if(k==1){ 105 q[i].type=1;q[i].x=a;q[i].y=b;q[i].w=n-c+1; 106 } 107 else{ 108 q[i].type=2;q[i].x=a;q[i].y=b;q[i].w=c;q[i].id=++tot; 109 } 110 } 111 solve(1,m,-n,n); 112 for(long long i=1;i<=tot;i++){ 113 printf("%lld\n",n-ans[i]+1); 114 } 115 return 0; 116 }

BZOJ 3110 [Zjoi2013]K大數查詢(整體二分)