zoukankan      html  css  js  c++  java
  • 线段树+主席树笔记

    对不起,会打线段树是真的可以为所欲为的

    线段树单点更新

     1 //求区间最值
     2 //n个元素,m个询问
     3 //C x y 代表将第x个元素的值改为y
     4 //D x y 代表在第x到第y个元素中找最大值 
     5 //X x y 代表在第x到第y个元素中找最小值
     6 #include<iostream>
     7 #include<cstring>
     8 #include<cstdio>
     9 #include<cmath>
    10 using namespace std;
    11 struct tree_node{
    12     int maxn,minn;
    13 }t[400001];
    14 int n,m,x,y,a[100001];
    15 char ord[5];
    16 void build(int l,int r,int u){
    17     if(l==r){
    18         t[u].maxn=a[l];
    19         t[u].minn=a[l];
    20         return;
    21     }
    22     int mid=(l+r)/2;
    23     build(l,mid,u*2);
    24     build(mid+1,r,u*2+1);
    25     t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
    26     t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
    27 }
    28 void updata(int l,int r,int u,int x,int y){
    29     if(l==r){
    30         t[u].maxn=y;
    31         t[u].minn=y;
    32         return;
    33     }
    34     int mid=(l+r)/2;
    35     if(x<=mid)updata(l,mid,u*2,x,y);
    36     else if(x>mid)updata(mid+1,r,u*2+1,x,y);
    37     t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
    38     t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
    39 }
    40 int query_max(int l,int r,int u,int L,int R){
    41     if(l>=L&&r<=R){
    42         return t[u].maxn;
    43     }
    44     int mid=(l+r)/2,ans=-2147483647;
    45     if(L<=mid)ans=max(ans,query_max(l,mid,u*2,L,R));
    46     if(R>mid)ans=max(ans,query_max(mid+1,r,u*2+1,L,R));
    47     return ans;
    48 }
    49 int query_min(int l,int r,int u,int L,int R){
    50     if(l>=L&&r<=R){
    51         return t[u].minn;
    52     }
    53     int mid=(l+r)/2,ans=2147483647;
    54     if(L<=mid)ans=min(ans,query_min(l,mid,u*2,L,R));
    55     if(R>mid)ans=min(ans,query_min(mid+1,r,u*2+1,L,R));
    56     return ans;
    57 }
    58 int main(){
    59     scanf("%d%d",&n,&m);
    60     for(int i=1;i<=n;i++){
    61         scanf("%d",&a[i]);
    62     }
    63     build(1,n,1);
    64     for(int i=1;i<=m;i++){
    65         scanf("%s",ord);
    66         scanf("%d%d",&x,&y);
    67         if(ord[0]=='C'){
    68             updata(1,n,1,x,y);
    69         }
    70         if(ord[0]=='D'){
    71             printf("%d
    ",query_max(1,n,1,x,y));
    72         }
    73         if(ord[0]=='X'){
    74             printf("%d
    ",query_min(1,n,1,x,y));
    75         }
    76     }
    77     return 0;
    78 }

    线段树区间修改

     1 //区间求和+区间修改
     2 //类似地,n个元素、m个询问 
     3 //Q x y表示询问x至y的和 
     4 //A x y z表示将x到y的值全部加上z
     5 #include<iostream>
     6 #include<cstring>
     7 #include<cstdio>
     8 #include<cmath>
     9 using namespace std;
    10 struct tree{
    11     int v,lazy;
    12 }t[400001];
    13 int n,m,x,y,z,a[100001];
    14 char ord[5];
    15 void pd(int u,int l,int r){
    16     if(t[u].lazy!=0){
    17         int mid=(l+r)/2;
    18         t[u*2].lazy+=t[u].lazy;
    19         t[u*2+1].lazy+=t[u].lazy;
    20         t[u*2].v+=t[u].lazy*(mid-l+1);
    21         t[u*2+1].v+=t[u].lazy*(r-mid);
    22         t[u].lazy=0;
    23     }
    24 }
    25 void build(int l,int r,int u){
    26     if(l==r){
    27         t[u].v=a[l];
    28         return;
    29     }
    30     int mid=(l+r)/2;
    31     t[u].lazy=0;
    32     build(l,mid,u*2);
    33     build(mid+1,r,u*2+1);
    34     t[u].v=t[u*2].v+t[u*2+1].v;
    35 }
    36 void updata(int l,int r,int u,int L,int R,int val){
    37     if(L<=l&&r<=R){
    38         t[u].lazy+=val;
    39         t[u].v+=val*(r-l+1);
    40         return;
    41     }
    42     pd(u,l,r);
    43     int mid=(l+r)/2;
    44     if(L<=mid)updata(l,mid,u*2,L,R,val);
    45     if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
    46     t[u].v=t[u*2].v+t[u*2+1].v;
    47 }
    48 int query(int l,int r,int u,int L,int R){
    49     if(L<=l&&r<=R){
    50         return t[u].v;
    51     }
    52     pd(u,l,r);
    53     int mid=(l+r)/2,ans=0;
    54     if(L<=mid)ans+=query(l,mid,u*2,L,R);
    55     if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
    56     t[u].v=t[u*2].v+t[u*2+1].v;
    57     return ans;
    58 }
    59 int main(){
    60     scanf("%d%d",&n,&m);
    61     for(int i=1;i<=n;i++){
    62         scanf("%d",&a[i]);
    63     }
    64     build(1,n,1);
    65     for(int i=1;i<=m;i++){
    66         scanf("%s%d%d",ord,&x,&y);
    67         if(ord[0]=='A'){
    68             scanf("%d",&z);
    69             updata(1,n,1,x,y,z);
    70         }
    71         if(ord[0]=='Q'){
    72             printf("%d
    ",query(1,n,1,x,y));
    73         }
    74     }
    75     return 0;
    76 }

    可持久化线段树单点修改

     1 //单点修改可持久化线段树(非主席树)
     2 //给出n个数,q个询问
     3 //每次询问形如 0 k l r 或 1 k i x
     4 //表示询问第k个版本l到r之间的最大值或把第k个版本的第i个数改为x
     5 //初始的n个数表示第一个版本 
     6 #include<iostream>
     7 #include<cstring>
     8 #include<cstdio>
     9 #include<cmath>
    10 using namespace std;
    11 struct node{
    12     int mx,ls,rs;
    13 }t[2000001];
    14 int n,q,k,l,r,ord,cnt=0,tot=0,rt[100001],num[100001];
    15 void build(int l,int r,int &u){
    16     if(!u)u=++tot;
    17     if(l==r){
    18         t[u].mx=num[l];
    19         return;
    20     }
    21     int mid=(l+r)/2;
    22     build(l,mid,t[u].ls);
    23     build(mid+1,r,t[u].rs);
    24     t[u].mx=max(t[t[u].ls].mx,t[t[u].rs].mx);
    25 }
    26 void ins(int &k,int last,int l,int r,int p,int x){
    27     t[k=++tot].mx=t[last].mx;
    28     if(l==r){
    29         t[k].mx=x;
    30         return;
    31     }
    32     t[k].ls=t[last].ls;
    33     t[k].rs=t[last].rs;
    34     int mid=(l+r)/2;
    35     if(p<=mid)ins(t[k].ls,t[last].ls,l,mid,p,x);
    36     else ins(t[k].rs,t[last].rs,mid+1,r,p,x);
    37     t[k].mx=max(t[t[k].ls].mx,t[t[k].rs].mx);
    38 }
    39 int query(int &k,int l,int r,int L,int R){
    40     if(!k)return 0;
    41     if(L==l&&r==R){
    42         return t[k].mx;
    43     }
    44     int mid=(l+r)/2;
    45     if(R<=mid)return query(t[k].ls,l,mid,L,R);
    46     else if(L>mid)return query(t[k].rs,mid+1,r,L,R);
    47     else return max(query(t[k].ls,l,mid,L,mid),query(t[k].rs,mid+1,r,mid+1,R));
    48 }
    49 int main(){
    50     scanf("%d%d",&n,&q);
    51     for(int i=1;i<=n;i++){
    52         scanf("%d",&num[i]);
    53     }
    54     build(1,n,rt[++cnt]);
    55     for(int i=1;i<=q;i++){
    56         scanf("%d%d%d%d",&ord,&k,&l,&r);
    57         if(ord==1){
    58             ins(rt[++cnt],rt[k],1,n,l,r);
    59         }else{
    60             printf("%d
    ",query(rt[k],1,n,l,r));
    61         }
    62     }
    63     return 0;
    64 }

    可持久化线段树区间修改

     1 //hdu4348
     2 //标记永久化是真的省空间!!! 
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 using namespace std;
     8 typedef long long ll;
     9 struct node{
    10     int ls,rs;
    11     ll v,lazy;
    12 }t[5000001];
    13 int n,m,k,l,r,v,tot,cnt,num[100001],rt[100001];
    14 char ord[3];
    15 int build(int l,int r){
    16     int u=++tot;
    17     t[u].lazy=0;
    18     if(l==r){
    19         t[u].v=num[l];
    20         return u;
    21     }
    22     int mid=(l+r)/2;
    23     t[u].ls=build(l,mid);
    24     t[u].rs=build(mid+1,r);
    25     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    26     return u;
    27 }
    28 int rebuild(int l,int r,int L,int R,int v,int k){
    29     int u=++tot;
    30     t[u].v=t[k].v;
    31     t[u].ls=t[k].ls;
    32     t[u].rs=t[k].rs;
    33     t[u].lazy=t[k].lazy;
    34     if(l==L&&r==R){
    35         t[u].lazy+=v;
    36         t[u].v+=v*(r-l+1);
    37         return u;
    38     }
    39     int mid=(l+r)/2;
    40     if(R<=mid)t[u].ls=rebuild(l,mid,L,R,v,t[k].ls);
    41     else if(L>mid)t[u].rs=rebuild(mid+1,r,L,R,v,t[k].rs);
    42     else{
    43         t[u].ls=rebuild(l,mid,L,mid,v,t[k].ls);
    44         t[u].rs=rebuild(mid+1,r,mid+1,R,v,t[k].rs);
    45     }
    46     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    47     t[u].v+=t[u].lazy*(r-l+1);
    48     return u;
    49 }
    50 ll query(int l,int r,int u,int L,int R){
    51     if(l==L&&r==R){
    52         return t[u].v;
    53     }
    54     int mid=(l+r)/2;
    55     ll ans=0;
    56     if(L>=l&&R<=r)ans+=t[u].lazy*(R-L+1);
    57     else if(L<l&&R>=l&&R<=r)ans+=t[u].lazy*(R-l+1);
    58     else if(R>r&&L>=l&&L<=r)ans+=t[u].lazy*(r-L+1);
    59     else if(L<l&&R>r)ans+=t[u].lazy*(r-l+1);
    60     if(R<=mid)ans+=query(l,mid,t[u].ls,L,R);
    61     else if(L>mid)ans+=query(mid+1,r,t[u].rs,L,R);
    62     else ans+=query(l,mid,t[u].ls,L,mid)+query(mid+1,r,t[u].rs,mid+1,R);
    63     return ans;
    64 }
    65 int main(){
    66     while(scanf("%d%d",&n,&m)!=EOF){
    67         tot=cnt=0;
    68         for(int i=1;i<=n;i++){
    69             scanf("%d",&num[i]);
    70         }
    71         rt[0]=build(1,n);
    72         for(int i=1;i<=m;i++){
    73             scanf("%s",ord);
    74             if(ord[0]=='C'){
    75                 scanf("%d%d%d",&l,&r,&v);
    76                 rt[cnt+1]=rebuild(1,n,l,r,v,rt[cnt]);
    77                 cnt++;
    78             }else if(ord[0]=='Q'){
    79                 scanf("%d%d",&l,&r);
    80                 printf("%lld
    ",query(1,n,rt[cnt],l,r));
    81             }else if(ord[0]=='H'){
    82                 scanf("%d%d%d",&l,&r,&v);
    83                 printf("%lld
    ",query(1,n,rt[v],l,r));
    84             }else{
    85                 scanf("%d",&v);
    86                 cnt=v;
    87             }
    88         }
    89     }
    90     return 0;
    91 }

    主席树求区间k大

     1 //Orz hjt
     2 //其实和可持久化线段树是还是有点区别的QAQ 
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstring>
     6 #include<cstdio>
     7 #include<cmath>
     8 using namespace std;
     9 struct node{
    10     int ls,rs,v;
    11 }t[2000001];
    12 int n,q,k,l,r,pos,tot=0,cnt=0,a[100001],b[100001],rt[100001];
    13 int build(int l,int r){
    14     int u=++tot;
    15     t[u].v=0;
    16     if(l==r)return u;
    17     int mid=(l+r)/2;
    18     t[u].ls=build(l,mid);
    19     t[u].rs=build(mid+1,r);
    20     return u;
    21 }
    22 int ins(int l,int r,int k,int p){
    23     int u=++tot;
    24     t[u].ls=t[k].ls;
    25     t[u].rs=t[k].rs;
    26     t[u].v=t[k].v+1;
    27     if(l==r)return u;
    28     int mid=(l+r)/2;
    29     if(p<=mid)t[u].ls=ins(l,mid,t[k].ls,p);
    30     else t[u].rs=ins(mid+1,r,t[k].rs,p);
    31     return u;
    32 }
    33 int query(int l,int r,int pre,int now,int k){
    34     if(t[now].ls==t[now].rs){
    35         return b[l];
    36     }
    37     int mid=(l+r)/2,tmp=t[t[now].ls].v-t[t[pre].ls].v;
    38     if(tmp>=k)return query(l,mid,t[pre].ls,t[now].ls,k);
    39     else return query(mid+1,r,t[pre].rs,t[now].rs,k-tmp);
    40 }
    41 int main(){
    42     scanf("%d%d",&n,&q);
    43     for(int i=1;i<=n;i++){
    44         scanf("%d",&a[i]);
    45         b[i]=a[i];
    46     }
    47     sort(b+1,b+n+1);
    48     rt[0]=build(1,n);
    49     for(int i=1;i<=n;i++)rt[i]=ins(1,n,rt[i-1],lower_bound(b+1,b+n+1,a[i])-b);
    50     for(int i=1;i<=q;i++){
    51         scanf("%d%d%d",&l,&r,&k);
    52         printf("%d
    ",query(1,n,rt[l-1],rt[r],k));
    53     }
    54     return 0;
    55 }

    带修改区间k大(线段树套平衡树)

    见这篇博客

  • 相关阅读:
    今天博客开通第一天,以此纪念!
    基于opencv的车牌识别系统
    【C和指针】笔记1
    【局域网聊天客户端篇】基于socket与Qt
    对Qt下对话服务器客户端的总结(MyTcpServer与MyTcpClient)
    linux 线程编程详解
    【linux】安装samba服务
    linux(ubuntu)获取命令源码方式
    win7下用SSH连接linux虚拟机
    Linux下deb包安装工具(附带安装搜狗输入法)
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/8945232.html
Copyright © 2011-2022 走看看