1. 程式人生 > >HYSBZ - 3110 K大數查詢 (樹套樹)

HYSBZ - 3110 K大數查詢 (樹套樹)

clas scanf code com geo return tps pri ble

題目鏈接

權值線段樹套區間線段樹,權值線段樹的每個結點存儲該結點所表示的區間範圍內的數在各個區間的分布情況,查詢時在權值線段樹上二分即可。復雜度$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 }

HYSBZ - 3110 K大數查詢 (樹套樹)