线段树&树状数组总结篇

1、 入门题:hdu1166敌兵布阵

单点更新区间求和

线段树:

using namespace std;
struct node
{
     int l,r,sum;
}num[maxn*4];
int m[maxn];
char s[10];
int t,n,a,b;
void build(int root,int l,int r)
{
     num[root].l=l;
     num[root].r=r;
     if(num[root].l==num[root].r)
     {
          num[root].sum=m[l];return;
     }
     int mid=(num[root].l+num[root].r)/2;
     build(root<<1,l,mid);
     build(root<<1|1,mid+1,r);
     num[root].sum=num[root<<1].sum+num[root<<1|1].sum;
}
void update(int root,int pos,int data)
{
     if(num[root].l==num[root].r)
     {
          num[root].sum=data;
          return;
     }
     int mid=(num[root].l+num[root].r)/2;
     if(pos<=mid) update(root<<1,pos,data);
     else update(root<<1|1,pos,data);
     num[root].sum=num[root<<1].sum+num[root<<1|1].sum;
}
int  query(int root,int L,int R)
{
     if(L<=num[root].l&&R>=num[root].r)
     {
          return num[root].sum;
     }
     int mid=(num[root].l+num[root].r)/2;
     int ans=0;
     if(L<=mid) ans+=query(root<<1,L,R);
     if(R>mid) ans+=query(root<<1|1,L,R);
     return ans;
}

int main()
{
     freopen("data.in.txt","r",stdin);
     while(~scanf("%d",&t))
     {
          int cnt=1;
          while(t--)
          {
               scanf("%d",&n);
               for(int i=1;i<=n;i++)      scanf("%d",&m[i]);
               build(1,1,maxn);
               printf("Case %d: \n",cnt++);
               while(~scanf("%s",s))
               {
                    if(strcmp(s,"END")==0) break;
                    scanf("%d%d",&a,&b);
                    if(strcmp(s,"Add")==0)
                    {
                         m[a]+=b;
                         update(1,a,m[a]);
                    }
                    if(strcmp(s,"Sub")==0)
                    {
                         m[a]-=b;
                         update(1,a,m[a]);
                    }
                    if(strcmp(s,"Query")==0)
                    {
                         if(a>b) swap(a,b);
                         printf("%d\n",query(1,a,b));
                    }
               }
          }
     }
     return 0;
}

树状数组

int lowbit(int i)
{
     return i&(-i);
}
void update(int i,int x)
{
     while(i<=n)
     {
          tree[i]+=x;
          i+=lowbit(i);
     }
}
int query(int n)
{
     int sum=0;
     while(n>0)
     {
          sum+=tree[n];
          n-=lowbit(n);
     }
     return sum;
}
int main()
{
    int t;scanf("%d",&t);
    for(int cas=1;cas<=T;cas++)
    {
         memset(tree,0,sizeof(tree));
         scanf("%d",&n);
         for(int i=1;i<=n;i++)
         {
              int x;scanf("%d",&x);
              update(i,x);
         }
         char str[10];
         while(~scanf("%s",str)&&strcmp(str,"END"))
         {
             inta,b;scanf("%d%d",&a,&b);
              if(str[0]=='Q')
printf("%d\n",Query(b)-Query(a-1));
            elseif(str[0]=='S')Update(a,-b);
              else Update(a,b);
         }
    }
    return 0;
}

2、懒惰标记入门题: hdu1698 just a hook

区间更新求总和 ,不写懒惰标记也能过==看我的这篇

#include 
#include 
using namespace std;
const int maxn=1e5+5;
#define l_t 2*root
#define r_t 2*root+1
struct node{
    int l,r,val,tag;  //tag:1 2 3 -1
    int mid(){  return (l+r)/2; }
}tree[maxn<<2];
void update(int a,int b,int root,int tg){
    if(a==tree[root].l&&b==tree[root].r){
         tree[root].tag=tg;
         tree[root].val=(tree[root].r-tree[root].l+1)*tg;
         return ;
    }
    if(tree[root].tag!=-1){
         tree[l_t].tag=tree[root].tag;
         tree[l_t].val=tree[l_t].tag*(tree[l_t].r-tree[l_t].l+1);
         tree[r_t].tag=tree[root].tag;
         tree[r_t].val=tree[r_t].tag*(tree[r_t].r-tree[r_t].l+1);
         tree[root].tag=-1;
    }
    int m=tree[root].mid();
    if(a>m) update(a,b,r_t,tg);
    else if(b<=m) update(a,b,l_t,tg);
    else {
        update(a,m,l_t,tg);
        update(m+1,b,r_t,tg);
    }
    tree[root].val=tree[l_t].val+tree[r_t].val;
}
void build(int l,int r,int root){
    tree[root].l=l;
    tree[root].r=r;
    tree[root].tag=-1;
    if(r==l){
        tree[root].val=1;
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,l_t);
    build(mid+1,r,r_t);
    tree[root].val=tree[l_t].val+tree[r_t].val;
}

int main()
{
    //freopen("cin.txt","r",stdin);
    int ca;
    cin>>ca;
    for(int k=1;k<=ca;k++){
        int n,q;
        scanf("%d",&n);
        build(1,n,1);
        scanf("%d",&q);
        for(int i=0;i

3、线段树求逆序数: hdu1394minimum inversion number

求依次把数组的第一个数放到最后,组成的新数组的逆序数的最小值。给定的数是0~n-1之间的。

整体的思路是先求出来把每个数插到最后相对比放在原始位置变动的多少,这个相对值+原始的逆序数值就是最终结果。关键是相对值如何求?由于每个数都是0~n-1之间,省了离散化这个步骤,我们知道n-1-a[i]是比这个数大的个数,也就是这个数后面有多少个比大的,(我们让每步的初始状态是读入的这个数是第一个)那么我们把这个刚刚读入的数放到最后,里外里就为逆序数贡献了n-1-2*a[i],中间的不用管,反正没为逆序数总值做贡献。   可以看我这篇:感觉写的还没有我这个详细呢

hdu1394Minimum Inversion Number逆序数

#include 
#include
using namespace std;
struct node
{
    int l,r,sum;
}tree[150000];
void build(int root,int l,int r)
{
    tree[root].l=l,tree[root].r=r;
    if(tree[root].l==tree[root].r)
    {
        tree[root].sum=0;
        return;
    }
    build(root<<1,l,(l+r)/2);
    build(root<<1|1,(l+r)/2+1,r);
    tree[root].sum=0;
}
void update(int root,int pos,int val)
{
    if(tree[root].l==tree[root].r)
    {
        tree[root].sum=val;
        return;
    }
    int mid=(tree[root].l+tree[root].r)/2;
    if(pos<=mid) update(root<<1,pos,val);
    else update(root<<1|1,pos,val);///这里写成了build 你脑子在想什么==
    tree[root].sum=min(tree[root<<1].sum,tree[root<<1|1].sum);
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n,a[12],ret;///
    while(~scanf("%d",&n))
    {
        build(1,1,n);
        ret=0;
        for(int i=0;ia[j]) ret++;
            }
        }
        printf("%d\n",ret+tree[1].sum);
    }
    return 0;
}

4、懒惰标记经典题: poj3667hotel

 题意:旅馆有人开房:给定区间长度,尽量从小号开始给连续的房间,询问最左侧的房间号、有人退房:给定左区间端点和区间长度

现在看来也没什么好说的,注意题中要求的顺序

#include 
#include
#include
using namespace std;
struct node
{
    int l,r,lsum,rsum,sum,loop;
}tree[400000];
int Find_Max(int a,int b ,int c)
{
    int maxn=a>b?a:b;
    maxn=maxn>c?maxn:c;
    return maxn;
}
void push_down(int t)
{
    if(tree[t].loop!=-1)
    {
        tree[t<<1].loop=tree[t<<1|1].loop=tree[t].loop;
        if(tree[t].loop)
        {
            tree[t<<1].lsum=tree[t<<1].rsum=tree[t<<1].sum=0;
            tree[t<<1|1].lsum=tree[t<<1|1].rsum=tree[t<<1|1].sum=0;
        }
        else //if(tree[t].loop==0)
        {
            tree[t<<1].lsum=tree[t<<1].rsum=tree[t<<1].sum=tree[t<<1].r-tree[t<<1].l+1;
            tree[t<<1|1].lsum=tree[t<<1|1].rsum=tree[t<<1|1].sum=tree[t<<1|1].r-tree[t<<1|1].l+1;
        }
        tree[t].loop=-1;
    }
}
void push_up(int l,int r,int t)
{
    tree[t].lsum=tree[t<<1].lsum;
    tree[t].rsum=tree[t<<1|1].rsum;
    int x=(l+r)/2;
    if(tree[t].lsum==x-l+1) tree[t].lsum+=tree[t<<1|1].lsum;
    if(tree[t].rsum==r-x) tree[t].rsum+=tree[t<<1].rsum;
    tree[t].sum=Find_Max(tree[t<<1].sum,tree[t<<1|1].sum,tree[t<<1].rsum+tree[t<<1|1].lsum);///
}
void build(int l,int r,int t)
{
    tree[t].l=l,tree[t].r=r;
    tree[t].sum=tree[t].lsum=tree[t].rsum=r-l+1;
    tree[t].loop=-1;
    if(l==r) return;
    int x=(l+r)/2;
    build(l,x,2*t);
    build(x+1,r,2*t+1);
}
void update_tree(int l,int r,int t,int cnt)
{
    if(tree[t].l==l&&tree[t].r==r)
    {
        tree[t].loop=cnt;
        if(cnt) tree[t].lsum=tree[t].rsum=tree[t].sum=0;
        else tree[t].lsum=tree[t].rsum=tree[t].sum=r-l+1;
        return;
    }
    push_down(t);
    int x=(tree[t].l+tree[t].r)/2;
    if(x>=r) update_tree(l,r,2*t,cnt);
    else if(x+1<=l) update_tree(l,r,2*t+1,cnt);
    else
    {
        update_tree(l,x,2*t,cnt);
        update_tree(x+1,r,t<<1|1,cnt);
    }
    push_up(tree[t].l,tree[t].r,t);
}
int Query(int l,int r,int t,int cnt)
{
    if(l==r) return 1;
    int x=(l+r)/2;
    push_down(t);
    if(tree[t<<1].sum>=cnt) return Query(l,x,t<<1,cnt);
    else if(tree[t<<1].rsum+tree[t<<1|1].lsum>=cnt)return x-tree[t<<1].rsum+1;
    else return Query(x+1,r,t<<1|1,cnt);
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int i,j,n,m,x,y;
    while(~scanf("%d%d",&n,&m))
    {
        build(1,n,1);
        while(m--)
        {
            scanf("%d",&i);
            if(i==1)
            {
                scanf("%d",&x);
                if(tree[1].sum

6、 hdu2795billbroad

展板上贴窄公告,优先选择最上最左的,输出行号。和刚刚那个题一样,也需要注意优先级的问题,更要注意长度是有限制的,不像上面那个是一维的

#include 
#include
#include
#define maxn 200000
using namespace std;
struct bill
{
     int l,r,ans;
}num[maxn*4];
int m;
int w,h,n;
void build(int L,int R,int root)
{
     num[root].l=L;
     num[root].r=R;
     num[root].ans=w;
     if(L==R) return;
     build(L,(L+R)/2,root<<1);
     build((L+R)/2+1,R,root<<1|1);
    //
}
int update(int root,int m)
{
     if(num[root].ans=m) ret=update(root<<1,m);
     else ret=update(root<<1|1,m);
     num[root].ans=max(num[root<<1].ans,num[root<<1|1].ans);
     return ret;
}
int main()
{
    //freopen("data.in.txt","r",stdin);
    while(~scanf("%d%d%d",&h,&w,&n))
    {
         build(1,min(n,h),1);
         for(int i=1;i<=n;i++)
         {
              scanf("%d",&m);
              printf("%d\n",update(1,m));
         }
    }
    return 0;
}
===================================上面都是去年暑假做的水题,下面的是今年的练习,难度明显高了一个level======================================
7、树状数组、线段树求逆序数:poj2299Ultra-QuickSort 求交换相邻的数字使之有序的次数

简而言之就是交换次数==每个数前面比他大的总和 详细的代码见:

poj2299Ultra-QuickSort【树状数组求逆序数、离散化】、【归并排序模板】

#include 
#include
#include
#include
using namespace std;
#define maxn 500005
int n;
int c[maxn],b[maxn];
struct Node
{
    int index,v;
}node[maxn];
bool cmp(Node a,Node b)
{
    return a.v0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&node[i].v);
            node[i].index=i;
        }
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        sort(node+1,node+1+n,cmp);
        b[node[1].index]=1;
        for(int i=2;i<=n;i++)
        {
            b[node[i].index]=i;
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            add(b[i],1);
            ans+=(i-sum(b[i]));
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
线段树做法

#include 
#include
#include
#include
using namespace std;
#define maxn 500005
struct node
{
    int id,val;
}num[maxn];
bool cmp(node n1,node n2)
{
    return n1.valmid) sum=query(rt<<1|1,l,r);
    else
        sum=query(rt<<1,l,mid)+query(rt<<1|1,mid+1,r);
    return sum;
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int n;
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0;i


树状数组区间更新单点求值hdu4267 点击我看博客

A Simple Problem with Integers

#include
#include
using namespace std;
int n,q,c[12][12][50010],tmp[50010];
int lowbit(int i)
{
    return i&(-i);
}
void add(int t1,int t2,int i,int x)
{
    while(i>0)
    {
        c[t1][t2][i]+=x;
        i-=lowbit(i);
    }
}
int query(int t1,int t2,int x)
{
    int s=0;
    while(x<=n)
    {
        s+=c[t1][t2][x];
        x+=lowbit(x);
    }
    return s;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        memset(c,0,sizeof(c));
        int a,b,k,e,m;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&tmp[i]);
        }
   //     for(int i=1;i<=n;i++) printf("%d  ",c[i]);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&m);
            if(m==1)
            {
                scanf("%d%d%d%d",&a,&b,&k,&e);
                int num=(b-a)/k;
                int s=a%k;
                add(k,s,a-1,-e);
                add(k,s,b,e);
            }
            else
            {
                scanf("%d",&a);
                int sum=tmp[a];
                for(int i=1;i<=10;i++)
                {
                    sum+=query(i,a%i,a);
                }
                printf("%d\n",sum);
            }
        }
    }
    return 0;
}

9.二维树状数组 单点更新 区间求值

poj1195Mobile phones【二维树状数组。单点更新/区间求和】

#include 
#include
#include
using namespace std;
int tree[1050][1050],n,t,x,y,a,l,b,r,cmd;
int lowbit(int i)
{
    return i&(-i);
}
void update(int x,int y,int a)
{
    for(int i=x;i<=n;)
    {
        for(int j=y;j<=n;)
        {
            tree[i][j]+=a;
            j+=lowbit(j);
        }
        i+=lowbit(i);
    }
}
int query(int x,int y)
{
    int s=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        for(int j=y;j>0;j-=lowbit(j))
        s+=tree[i][j];
    }
    return s;
}
int main()
{
   // freopen("cin.txt","r",stdin);
    scanf("%d%d",&cmd,&n);
    memset(tree,0,sizeof(tree));
    while(~scanf("%d",&cmd))
    {
        if(cmd==3) break;
        if(cmd==1)
        {
            scanf("%d%d%d",&x,&y,&a);
            x++;y++;
            update(x,y,a);
        }
        else
        {
            scanf("%d%d%d%d",&l,&b,&r,&t);
            int sum=0;
            l++;b++;r++;t++;
            sum=query(r,t)+query(l-1,b-1)-query(l-1,t)-query(r,b-1);
            printf("%d\n",sum);
        }
    }
    return 0;
}

10、离散化区间更新线段树。贴布条

poj2528Mayor's posters【离散化线段树区间更新】

既然说了新贴的贴到原来的上面,那么新贴的染新色最后看有多少颜色就得了啊

hdu4027Can you answer these queries?【线段树区间更新区间求和】更新是区间内的值都开根号


#include 
#include 
#include
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 11111;
bool hash[maxn];
int li[maxn] , ri[maxn];
int X[maxn*3];
int col[maxn<<4];
int cnt;
void push_down(int rt)
{
    if(col[rt]!=-1)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        col[rt]=-1;
    }
}
void update(int l,int r,int c,int L,int R,int rt)
{
    if(l<=L&&R<=r)
    {
        col[rt]=c;
        return;
    }
    push_down(rt);
    int mid=(L+R)/2;
    if(l<=mid)update(l,r,c,L,mid,rt<<1);
    if(r>mid) update(l,r,c,mid+1,R,rt<<1|1);///
}
void query(int l,int r,int rt)
{
    if(col[rt]!=-1)
    {
        if(!hash[col[rt]]) cnt++;
        hash[col[rt]]=1;
        return;
    }
    if(l==r) return;
    int m=(l+r)/2;
    query(l,m,rt<<1);
    query(m+1,r,rt<<1|1);
}
int Bin(int num,int R)
{
    int l=0,r=R-1,mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(X[mid]==num) return mid;
        if(X[mid]0;i--)if(X[i]!=X[i-1]+1)X[m++]=X[i-1]+1;
        sort(X,X+m);
        memset(col,-1,sizeof(col));
        for(int i=0;i

11、线段树区间更新区间求和 区间更新是开根号,注意算到一就结束了啊

hdu4027Can you answer these queries?【线段树区间更新区间求和】

#include 
#include
#include
#include
using namespace std;
struct node
{
    int l,r;
    long long sum;
}num[400005];
int n,m,t;
void build(int l,int r,int i)
{
    num[i].l=l;
    num[i].r=r;
    if(l==r)
    {
        scanf("%I64d",&num[i].sum);
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    num[i].sum=num[i<<1].sum+num[i<<1|1].sum;
}
void update(int l,int r,int rt)
{
    if(num[rt].sum==(num[rt].r-num[rt].l+1)&&l==num[rt].l&&r==num[rt].r)
     return;
    if(num[rt].l==num[rt].r)
    {
        num[rt].sum=(int)sqrt(num[rt].sum*1.0);
        return;
    }
    int mid=(num[rt].l+num[rt].r)/2;
    if(r<=mid) update(l,r,rt<<1);
    else if(l>mid) update(l,r,rt<<1|1);
    else
    {
        update(l,mid,rt<<1);
        update(mid+1,r,rt<<1|1);
    }
    num[rt].sum=num[rt<<1].sum+num[rt<<1|1].sum;
}
long long query(int l,int r,int rt)
{
    if(l==num[rt].l&&r==num[rt].r) return num[rt].sum;
    long long ans=0;
    int mid=(num[rt].l+num[rt].r)/2;
    if(r<=mid) ans+=query(l,r,rt<<1);
    else if(l>mid) ans+=query(l,r,rt<<1|1);
    else
    {
        ans+=query(l,mid,rt<<1);
        ans+=query(mid+1,r,rt<<1|1);
    }
    return ans;
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int cas=1;
    while(~scanf("%d",&n))
    {
        printf("Case #%d:\n",cas++);
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            int a,b;
            scanf("%d%d%d",&t,&a,&b);
            if(a>b) swap(a,b);
            if(t==0) update(a,b,1);
            else printf("%I64d\n",query(a,b,1));
        }
        puts("");
    }
    return 0;
}

12、线段树求第k大、第k小、维护区间最值

hdu2852KiKi's K-Number【线段树第k小】

#include 
#include
#include
using namespace std;
struct node
{
    int l,r,tot;
}num[800000];
int tmp;
void build(int rt,int l,int r)
{
    num[rt].l=l;num[rt].r=r;
    if(l==r)
    {
        num[rt].tot=0;
        return;
    }
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    num[rt].tot=0;
}
void update(int rt,int pos,bool flag)///1:add 0:del
{
    if(num[rt].l==num[rt].r)
    {
        if(flag) num[rt].tot++;
        else num[rt].tot--;
        return;///!!!
    }
    int mid=(num[rt].l+num[rt].r)/2;
    if(pos<=mid) update(rt<<1,pos,flag);
    else update(rt<<1|1,pos,flag);
    num[rt].tot=num[rt<<1].tot+num[rt<<1|1].tot;
}
int sum(int rt,int l,int r)
{
    if(num[rt].rr) return 0;
    if(num[rt].r<=r&&num[rt].l>=l) return num[rt].tot;
    int mid=(num[rt].l+num[rt].r)/2;
    return sum(rt<<1,l,r)+sum(rt<<1|1,l,r);
}
void query(int rt,int ans)
{
    if(ans>num[rt<<1].tot)
    {
        if(num[rt].l==num[rt].r)
        {
            tmp=num[rt].r;
            return;
        }
        query(rt<<1|1,ans-num[rt<<1].tot);
    }
    else query(rt<<1,ans);
}
int main()
{
  //  freopen("cin.txt","r",stdin);
    int q,a,b,m;
    while(~scanf("%d",&m))
    {
        build(1,1,100000);
        while(m--)
        {
            scanf("%d",&q);
            if(q==0)
            {
                scanf("%d",&a);
                update(1,a,1);
            }
            else if(q==1)
            {
                scanf("%d",&a);
                if(sum(1,1,a)==sum(1,1,a-1)) printf("No Elment!\n");
                else update(1,a,0);
            }
            else
            {
                scanf("%d%d",&a,&b);
                {
                    int t=sum(1,1,a);
                    tmp=0;
                    query(1,t+b);
                    if(tmp==100000)printf("Not Find!\n");
                    else printf("%d\n",tmp);
                }
            }
        }
    }
    return 0;
}
hdu4006The kth great number【线段树第k大】
#include 
#include
#include
using namespace std;
#define maxn 1000000
struct node
{
    int l,r,tot;
}num[maxn*8];
void build(int rt,int l,int r)
{
    num[rt].l=l;num[rt].r=r;
    if(l==r)
    {
        num[rt].tot=0;
        return;
    }
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    num[rt].tot=0;
}
void update(int rt,int pos)
{
    if(num[rt].l==num[rt].r)
    {
        if(num[rt].l==pos) num[rt].tot++;
        return;
    }
    int mid=(num[rt].l+num[rt].r)/2;
    if(pos<=mid) update(rt<<1,pos);
    else update(rt<<1|1,pos);
    num[rt].tot=num[rt<<1].tot+num[rt<<1|1].tot;
}
int query(int rt,int k)
{
    if(k>num[rt<<1|1].tot)
    {
        if(num[rt].l==num[rt].r)
        {
            return num[rt].l;
        }
        query(rt<<1,k-num[rt<<1|1].tot);
    }
    else query(rt<<1|1,k);
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int n,k,a;
    char st[3];
    while(~scanf("%d%d",&n,&k))
    {
        build(1,1,maxn);
        while(n--)
        {
            scanf("%s",st);
            if(st[0]=='I')
            {
                scanf("%d",&a);
                update(1,a);
            }
            else printf("%d\n",query(1,k));
        }
    }
    return 0;
}

poj2823Sliding Window【线段树维护滚动区间最值】    也就是建好树之后区间查询就好

#include 
#include
#include
using namespace std;
struct Node
{
    int l,r,minn,maxn;
}num[4000000];
int cnt[1000000];
int min(int a,int b){if(ab)return a;return b;}
void build(int rt,int l,int r)
{
    num[rt].l=l;num[rt].r=r;
    if(l==r)
    {
        num[rt].maxn=cnt[l];
        num[rt].minn=cnt[l];
        return;
    }
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    num[rt].maxn=max(num[rt<<1].maxn,num[rt<<1|1].maxn);
    num[rt].minn=min(num[rt<<1].minn,num[rt<<1|1].minn);
}
int query1(int rt,int l,int r)
{
    if(num[rt].l==l&&num[rt].r==r)
        return num[rt].minn;
    int mid=(num[rt].l+num[rt].r)/2;
    if(r<=mid) return query1(rt<<1,l,r);
    else if(l>mid) return query1(rt<<1|1,l,r);
    else
    return min(query1(rt<<1,l,mid),query1(rt<<1|1,mid+1,r));
}
int query2(int rt,int l,int r)
{
    if(num[rt].l==l&&num[rt].r==r)
        return num[rt].maxn;
    int mid=(num[rt].l+num[rt].r)/2;
    if(r<=mid) return query2(rt<<1,l,r);
    else if(l>mid) return query2(rt<<1|1,l,r);
    else
    return max(query2(rt<<1,l,mid),query2(rt<<1|1,mid+1,r));
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)scanf("%d",&cnt[i]);
        build(1,1,n);
        for(int i=1;i<=n-k;i++)
            printf("%d ",query1(1,i,i+k-1));
        printf("%d\n",query1(1,n-k+1,n));
        for(int i=1;i<=n-k;i++)
            printf("%d ",query2(1,i,i+k-1));
        printf("%d\n",query2(1,n-k+1,n));
    }
    return 0;
}


13、单点更新,区间求最值 

poj2886Who Gets the Most Candies?【线段树单点更新】

除了涉及反素数,其他只是把删掉的小孩当前位清空而已

#include 
#include
#include
using namespace std;
#define maxn 500005
int a[37]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,
           55440,83160,110880,166320,221760,277200,332640,498960,500001};
int b[37]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,1314521};
char name[maxn][15];
int pos[maxn];
struct node
{
    int l,r,tot;
}num[maxn*4];
void build(int rt,int l,int r)
{
    int mid=(l+r)/2;
    num[rt].l=l;num[rt].r=r;
    if(l==r)
    {
        num[rt].tot=1;
        return;
    }
   // printf("rt=%d tot=%d\n",rt,num[rt].tot);
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    num[rt].tot=num[rt<<1].tot+num[rt<<1|1].tot;
}
int update(int rt,int k)
{
    num[rt].tot--;
    if(num[rt].l==num[rt].r)
        return num[rt].l;
    if(k<=num[rt<<1].tot) update(rt<<1,k);
    else update(rt<<1|1,k-num[rt<<1].tot);
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)scanf("%s%d",name[i],&pos[i]);
       // for(int i=1;i<=n;i++)printf("%s% d\n",name[i],pos[i]);
        build(1,1,n);
        int cnt=0;
        while(a[cnt]<=n) cnt++;
        cnt--;
        int ps=0;
        pos[ps]=0;
      //  printf("tot=%d\n",num[1].tot);
        for(int i=0;i0)
                k = ((k + pos[ps] - 2) % num[1].tot + num[1].tot) % num[1].tot + 1;
            else k = ((k + pos[ps] - 1) % num[1].tot + num[1].tot) % num[1].tot + 1;
           // cout<

14、

POJ 2155 Matrix 【二维线段树模板题】

#include 
#include 
#include 

using namespace std;
const int MAXN = 1010;
struct Nodey
{
    int l,r;
    int val;
};
int n;
int locx[MAXN],locy[MAXN];
struct Nodex
{
    int l,r;
    Nodey sty[MAXN*3];
    void build(int i,int _l,int _r)
    {
        sty[i].l = _l;
        sty[i].r = _r;
        sty[i].val = 0;
        if(_l == _r)
        {
            locy[_l] = i;
            return;
        }
        int mid = (_l + _r)>>1;
        build(i<<1,_l,mid);
        build((i<<1)|1,mid+1,_r);
    }
    void add(int i,int _l,int _r,int val)
    {
        if(sty[i].l == _l && sty[i].r == _r)
        {
            sty[i].val += val;
            return;
        }
        int mid = (sty[i].l + sty[i].r)>>1;
        if(_r <= mid)add(i<<1,_l,_r,val);
        else if(_l > mid)add((i<<1)|1,_l,_r,val);
        else
        {
            add(i<<1,_l,mid,val);
            add((i<<1)|1,mid+1,_r,val);
        }
    }
}stx[MAXN*3];
void build(int i,int l,int r)
{
    stx[i].l = l;
    stx[i].r = r;
    stx[i].build(1,1,n);
    if(l == r)
    {
        locx[l] = i;
        return;
    }
    int mid = (l+r)>>1;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
}
void add(int i,int x1,int x2,int y1,int y2,int val)
{
    if(stx[i].l == x1 && stx[i].r == x2)
    {
        stx[i].add(1,y1,y2,val);
        return;
    }
    int mid = (stx[i].l + stx[i].r)/2;
    if(x2 <= mid)add(i<<1,x1,x2,y1,y2,val);
    else if(x1 > mid)add((i<<1)|1,x1,x2,y1,y2,val);
    else
    {
        add(i<<1,x1,mid,y1,y2,val);
        add((i<<1)|1,mid+1,x2,y1,y2,val);
    }
}
int sum(int x,int y)
{
    int ret = 0;
    for(int i = locx[x];i;i >>= 1)
        for(int j = locy[y];j;j >>= 1)
            ret += stx[i].sty[j].val;
    return ret;
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int q;
        scanf("%d%d",&n,&q);
        build(1,1,n);
        char op[10];
        int x1,x2,y1,y2;
        while(q--)
        {
            scanf("%s",op);
            if(op[0] == 'C')
            {
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                add(1,x1,x2,y1,y2,1);
            }
            else
            {
                scanf("%d%d",&x1,&y1);
                if(sum(x1,y1)%2 == 0)printf("0\n");
                else printf("1\n");
            }
        }
        if(T)printf("\n");
    }
    return 0;
}
15、

hdu4325 Flowers【树状数组区间更新单点求值 离散化】

#include 
#include 
#include
using namespace std;
#define maxn 200008
int n,tree[maxn],X[maxn],li[maxn],ri[maxn],nn,m,mm,ma;
int lowbit(int i)
{
    return i&(-i);
}
void update(int i,int x)
{
    while(i<=ma)
    {
        tree[i]=tree[i]+x;
        i=i+lowbit(i);
    }
}
long long query(int n)
{
    long long sum=0;
    while(n>0)
    {
        sum+=tree[n];
        n=n-lowbit(n);
    }
    return sum;
}
int Bin(int num,int R)
{
    int l=0,r=R-1,mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(X[mid]==num) return mid;
        if(X[mid]0;i--)if(X[i]-X[i-1]>=1)X[m++]=X[i-1]+1;
        sort(X,X+m);
        ma=m+1;
      //  for(int i=0;i


16 扫描线

hdu 1828 Picture【扫描线求周长模板题】

POJ1151 (HDU 1542) Atlantis【矩形面积并,线段树+离散化+扫描线模板】

你可能感兴趣的:(———线段树,树状数组,~~~总结~~~)