BZOJ - 3110 K大数查询 (树套树)

题目链接

权值线段树套区间线段树,权值线段树的每个结点存储该结点所表示的区间范围内的数在各个区间的分布情况,查询时在权值线段树上二分即可。复杂度$O(nlog^2n)$

注意区间线段树需要动态开点,并且标记要永久化,否则会TLE。

另外就是sum可能会爆int,需要用long long存储。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef double db;
 5 const int N=5e4+10;
 6 #define lson (u<<1)
 7 #define rson (u<<1|1)
 8 #define mid ((l+r)>>1)
 9 int n,m,rt[N<<2],ls[N*200],rs[N*200],tot;
10 ll mk[N*200],sum[N*200];
11 int newnode() {int u=++tot; ls[u]=rs[u]=sum[u]=0; return u;}
12 void upd2(int L,int R,int x,int& u,int l=1,int r=n) {
13     if(!u)u=newnode();
14     if(l>=L&&r<=R) {sum[u]+=(r-l+1)*x; mk[u]+=x; return;}
15     if(l>R||r<L)return;
16     upd2(L,R,x,ls[u],l,mid),upd2(L,R,x,rs[u],mid+1,r);
17     sum[u]+=(ll)(min(r,R)-max(l,L)+1)*x;
18 }
19 ll qry2(int L,int R,int& u,int l=1,int r=n) {
20     if(l>=L&&r<=R)return sum[u];
21     if(l>R||r<L)return 0;
22     return qry2(L,R,ls[u],l,mid)+qry2(L,R,rs[u],mid+1,r)+(ll)(min(r,R)-max(l,L)+1)*mk[u];
23 }
24 void upd(int p,int L,int R,int u=1,int l=1,int r=n) {
25     upd2(L,R,1,rt[u]);
26     if(l==r)return;
27     p<=mid?upd(p,L,R,lson,l,mid):upd(p,L,R,rson,mid+1,r);
28 }
29 int qry(int L,int R,int k,int u=1,int l=1,int r=n) {
30     if(l==r)return l;
31     ll t=qry2(L,R,rt[rson]);
32     return k<=t?qry(L,R,k,rson,mid+1,r):qry(L,R,k-t,lson,l,mid);
33 }
34 int main() {
35     scanf("%d%d",&n,&m);
36     while(m--) {
37         int f,l,r,x;
38         scanf("%d%d%d%d",&f,&l,&r,&x);
39         if(f==1)upd(x,l,r);
40         else printf("%d\n",qry(l,r,x));
41     }
42     return 0;
43 }

 

转载于:https://www.cnblogs.com/asdfsag/p/10685630.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值