动态开点 加 权值线段树

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 (动态开点权值线段树 + 树状数组)

动态开点的权值线段树搞普通平衡树。。。补发一波

luogu3224 永无乡(动态开点,权值线段树合并)

权值线段树-动态开点-合并(P4556 [Vani有约会]雨天的尾巴

ICPC20昆明M——动态开点权值线段树(主席树)

权值线段树套序列线段树