3110: [Zjoi2013]K大数查询

来源:互联网 发布:软件制作平台 编辑:程序博客网 时间:2024/06/05 03:16

题目大意,带该段的区间第k大。

注意,一个位置上可以有多个数的,更改操作是增加新数,而不是覆盖。

备用知识:标记永久化点击打开链接(不用的话应该也可以,但空间会大)

然后就上权值线段树套区间线段树。

不修改的区间第k小是例题(类似二分),树套树可以解决修改的问题。

我们可以c+n+1转正,然后把求区间第k大变成(len-k+1)小。

答案再减回来就行了。

要用long long

code:

[cpp] view plain copy
  1. #include<cstdio>  
  2. #include<cstdlib>  
  3. #include<cstring>  
  4. #include<iostream>  
  5. #define LL long long  
  6. using namespace std;  
  7. int n,m,N;  
  8. struct node{  
  9.     int lc,rc;  
  10.     LL c,u;  
  11. }tr[20200010];int trlen=0,root[200010];  
  12. void update(int &x,int l,int r,int fl,int fr,LL c)  
  13. {  
  14.     if(!x) x=++trlen;  
  15.     if(l==fl&&r==fr){tr[x].u+=c;tr[x].c+=c*(r-l+1);return;}  
  16.     int mid=(l+r)/2;  
  17.     if(fr<=mid) update(tr[x].lc,l,mid,fl,fr,c);  
  18.     else if(fl>mid) update(tr[x].rc,mid+1,r,fl,fr,c);  
  19.     else update(tr[x].lc,l,mid,fl,mid,c),update(tr[x].rc,mid+1,r,mid+1,fr,c);  
  20.     tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c+(r-l+1)*tr[x].u;  
  21. }  
  22. LL findans(int x,int l,int r,int fl,int fr,LL u)  
  23. {  
  24.     if(!x) return u*(LL)(fr-fl+1);  
  25.     if(l==fl&&fr==r) return tr[x].c+(LL)(r-l+1)*u;  
  26.     int mid=(l+r)/2;  
  27.     if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr,u+tr[x].u);  
  28.     if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr,u+tr[x].u);  
  29.     return findans(tr[x].lc,l,mid,fl,mid,u+tr[x].u)+findans(tr[x].rc,mid+1,r,mid+1,fr,u+tr[x].u);  
  30. }  
  31. int bt(int l,int r)  
  32. {  
  33.     int x=++trlen;  
  34.     if(l!=r)  
  35.     {  
  36.         int mid=(l+r)/2;  
  37.         tr[x].lc=bt(l,mid);  
  38.         tr[x].rc=bt(mid+1,r);  
  39.     }  
  40.     return x;  
  41. }  
  42. void change(int x,int l,int r,int fl,int fr,int k,LL c)  
  43. {  
  44.     update(root[x],1,n,fl,fr,c);  
  45.     if(l==r) return;  
  46.     int mid=(l+r)/2;  
  47.     if(k<=mid) change(tr[x].lc,l,mid,fl,fr,k,c);  
  48.     else change(tr[x].rc,mid+1,r,fl,fr,k,c);  
  49. }  
  50. int solve(int x,int l,int r,int fl,int fr,LL k)  
  51. {  
  52.     if(l==r) return l;  
  53.     int mid=(l+r)/2;LL sum=findans(root[tr[x].lc],1,n,fl,fr,0LL);  
  54.     if(k<=sum) return solve(tr[x].lc,l,mid,fl,fr,k);  
  55.     else return solve(tr[x].rc,mid+1,r,fl,fr,k-sum);  
  56. }  
  57. int findnum(int l,int r,LL c)  
  58. {  
  59.     LL k=(findans(root[1],1,n,l,r,0)-c+1);  
  60.     if(k<=0) k=1;  
  61.     return solve(1,1,N,l,r,k)-n-1;  
  62. }  
  63. int main()  
  64. {  
  65.     scanf("%d %d",&n,&m);  
  66.     N=2*n+1;bt(1,N);  
  67.     for(int i=1;i<=m;i++)  
  68.     {  
  69.         int tmp,x,y,c;scanf("%d %d %d %d",&tmp,&x,&y,&c);  
  70.         if(tmp==1) change(1,1,N,x,y,c+n+1,1LL);  
  71.         else printf("%d\n",findnum(x,y,(LL)c));  
  72.     }  
  73. }  

数据生成器:

[cpp] view plain copy
  1. #include<cstdio>  
  2. #include<cstdlib>  
  3. #include<cstring>  
  4. #include<ctime>  
  5. #include<iostream>  
  6. #define LL long long  
  7. using namespace std;  
  8. struct node{  
  9.     int lc,rc;  
  10.     LL c,u;  
  11. }tr[400010];int trlen=0;  
  12. int n,m,root=0;  
  13. void update(int &x,int l,int r,int fl,int fr,LL c)  
  14. {  
  15.     if(!x) x=++trlen;  
  16.     if(l==fl&&r==fr){tr[x].u+=c;tr[x].c+=c*(r-l+1);return;}  
  17.     int mid=(l+r)/2;  
  18.     if(fr<=mid) update(tr[x].lc,l,mid,fl,fr,c);  
  19.     else if(fl>mid) update(tr[x].rc,mid+1,r,fl,fr,c);  
  20.     else update(tr[x].lc,l,mid,fl,mid,c),update(tr[x].rc,mid+1,r,mid+1,fr,c);  
  21.     tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c+(r-l+1)*tr[x].u;  
  22. }  
  23. LL findans(int x,int l,int r,int fl,int fr,LL u)  
  24. {  
  25.     if(!x) return u*(LL)(fr-fl+1);  
  26.     if(l==fl&&fr==r) return tr[x].c+(LL)(r-l+1)*u;  
  27.     int mid=(l+r)/2;  
  28.     if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr,u+tr[x].u);  
  29.     if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr,u+tr[x].u);  
  30.     return findans(tr[x].lc,l,mid,fl,mid,u+tr[x].u)+findans(tr[x].rc,mid+1,r,mid+1,fr,u+tr[x].u);  
  31. }  
  32. int main()  
  33. {  
  34.     srand(time(0));  
  35.     int n=7000,m=5000;  
  36.     printf("%d %d\n",n,m);  
  37.     for(int i=1;i<=m;i++)  
  38.     {  
  39.         int l=rand()%n+1,r=rand()%n+1,c=(rand()%9000-rand()%9000)%n;  
  40.         if(l>r) swap(l,r);  
  41.         int tmp=rand()%2+1;  
  42.         if(tmp==1) update(root,1,n,l,r,1LL);  
  43.         else  
  44.         {  
  45.             LL TMP=findans(root,1,n,l,r,0);  
  46.             if(TMP==0) tmp=1;  
  47.             else c=rand()%TMP+1;  
  48.         }  
  49.         printf("%d %d %d %d\n",tmp,l,r,c);  
  50.     }  
  51. }  

原创粉丝点击