动态开点 加 权值线段树
Posted suiyuemin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态开点 加 权值线段树相关的知识,希望对你有一定的参考价值。
~~### 小萌新 什么也不会 写得详细一些吧~~
【[BJOI2016]回转寿司】
首先,暴力查找--30分
然后,黑科技---权值线段树
s[]表示前缀和,题目要求的是有多少对(i,j)满足L≤s[j]-s[i]≤R(i<j),变形一下得到s[j]-R≤s[i]≤s[j]-L
因此我们只需要遍历一遍s[]数组,每次对于当前的前缀和s,我们先在线段树上查询区间[s-R,s-L]内有多少个数,然后再把s加入到线段树中,最终求和即可
参考
https://blog.csdn.net/blessLZH0108/article/details/77072022
一般的线段树储存一段线段的信息,
然后这里维护的是单纯的数字,其实本质上没啥差别、、
一般数字比较大,我们就要考虑动态开点,
因为只有当用到时才开,会节省很大空间,
对于这道题是n*log(1e14)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e5+50; 5 int tot; 6 const ll inf=10000000000+50; 7 ll rt; 8 ll lson[maxn*40*4],rson[maxn*40*4]; 9 struct tre 10 { 11 long long v; 12 13 }t[maxn*40*4]; 14 ll read() 15 { 16 char ch=getchar(); 17 ll f=1,ans=0; 18 while(ch<‘0‘ || ch>‘9‘) 19 { 20 if(ch==‘-‘) f=-1; 21 ch=getchar(); 22 } 23 while(ch>=‘0‘ && ch<=‘9‘) 24 { 25 ans=ans*10+ch-‘0‘; 26 ch=getchar(); 27 } 28 return ans*f; 29 } 30 ll query(ll &num,ll l,ll r,ll al,ll ar) 31 { 32 //cout<<"sa"; 33 if(!num) num=++tot; 34 //巧妙利用引用赋值左右儿子 35 if(l>=al && r<=ar) 36 { 37 /*cout<<al<<" "<<ar<<" "<<l<<" "<<r<<" "; 38 cout<<num<<" "; 39 cout<<t[num].v<<endl;*/ 40 return t[num].v; 41 } 42 ll mid=(l+r)>>1; 43 ll anss=0; 44 if(ar>mid) 45 { 46 anss+=query(rson[num],mid+1,r,al,ar); 47 //传入该节点左右儿子,在后次迭代更新 48 } 49 if(al<=mid) 50 { 51 anss+=query(lson[num],l,mid,al,ar); 52 } 53 return anss; 54 55 } 56 void update(ll &now,ll l,ll r,ll aim) 57 { 58 //cout<<"bug"; 59 if(!now) 60 now=++tot; 61 //没开但是要修改,就开一个 62 // 63 if(l==r) 64 { 65 t[now].v++; 66 return; 67 } 68 ll mid=l+r>>1; 69 70 if(aim<=mid) 71 update(lson[now],l,mid,aim); 72 else 73 update(rson[now],mid+1,r,aim); 74 75 t[now].v=t[lson[now]].v+t[rson[now]].v; 76 } 77 int main() 78 { 79 80 ll n,l,r; 81 n=read(); 82 l=read(); 83 r=read(); 84 /* for(int i=1;i<maxn*40;i++) 85 t[i].v=0;*/ 86 ll ans=0,num=0; 87 //update(rt,-inf,inf,num); 88 for(int i=1;i<=n;i++) 89 { 90 91 update(rt,-inf,inf,num); 92 num+=read(); 93 ans+=query(rt,-inf,inf,num-r,num-l); 94 // num+=read(); 95 /* 96 ans+=query(rt,-inf,inf,num-r,num-l); 97 update(rt,-inf,inf,num);*/ 98 99 } 100 cout<<ans; 101 return 0; 102 }
以上是关于动态开点 加 权值线段树的主要内容,如果未能解决你的问题,请参考以下文章
P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)