线段树&树状数组总结篇

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 <iostream>
#include <cstdio>
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<q;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            update(x,y,1,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",k,tree[1].val);
    }
    return 0;
}

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

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

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

hdu1394Minimum Inversion Number逆序数

#include <iostream>
#include<cstdio>
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;i<n;i++) {
            scanf("%d",&a[i]);
            ret+=(n-1-2*a[i]);
            update(1,a[i],ret);
        }
        ret=0;
        for(int i=0;i<n-1;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                if(a[i]>a[j]) ret++;
            }
        }
        printf("%d\n",ret+tree[1].sum);
    }
    return 0;
}

4、懒惰标记经典题: poj3667hotel

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

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

#include <iostream>
#include<cstring>
#include<cstdio>
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<x)
                {
                    printf("0\n");
                    continue;
                }
                y=Query(1,n,1,x);
                printf("%d\n",y);
                update_tree(y,y+x-1,1,1);
            }
            else
            {
                scanf("%d%d",&x,&y);
                update_tree(x,x+y-1,1,0);
            }
        }
    }
    return 0;
}

6、 hdu2795billbroad

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

#include <iostream>
#include<cstdio>
#include<cstring>
#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) return -1;
     if(num[root].l==num[root].r)
     {
          num[root].ans-=m;
          return num[root].l;
     }
     int ret;
     if(num[root<<1].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 <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
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.v<b.v;
}
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int val)
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        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 <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 500005
struct node
{
    int id,val;
}num[maxn];
bool cmp(node n1,node n2)
{
    return n1.val<n2.val;
}
struct Tree
{
    int l,r,tot;
}tree[maxn<<2];
int rank[maxn];
void build(int rt,int l,int r)
{
    tree[rt].l=l;tree[rt].r=r;
    tree[rt].tot=0;
    if(l==r)return;
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
void update(int rt,int x)
{
    tree[rt].tot++;
    if(tree[rt].l==tree[rt].r&&tree[rt].l==x)
        return;
    int mid=(tree[rt].l+tree[rt].r)/2;
    if(x<=mid)update(rt<<1,x);
    else update(rt<<1|1,x);
}
int query(int rt,int l,int r)
{
    int sum=0;
    if(tree[rt].l==l&&tree[rt].r==r)
        return tree[rt].tot;
    int mid=(tree[rt].l+tree[rt].r)/2;
    if(r<=mid) sum=query(rt<<1,l,r);
    else if(l>mid) 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<n;i++)
        {
            scanf("%d",&num[i].val);
            num[i].id=i;
        }
        sort(num,num+n,cmp);
        for(int i=0;i<n;i++) rank[num[i].id]=i+1;
        build(1,0,n+1);
        long long sum=0;
        for(int i=0;i<n;i++)
        {
            int x = rank[i];
            sum+=query(1,x+1,n+1);
            update(1,x);
        }
        printf("%I64d\n",sum);
    }
    return 0;
}


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

A Simple Problem with Integers

#include<cstdio>
#include<cstring>
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 <iostream>
#include<cstdio>
#include<cstring>
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 <cstdio>
#include <algorithm>
#include<cstring>
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]<num) l=mid+1;
        else r=mid-1;
    }
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        int nn=0,m=1;
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d%d",&li[i],&ri[i]),X[nn++]=li[i],X[nn++]=ri[i];
        sort(X,X+nn);
        for(int i=1;i<nn;i++)  if(X[i]!=X[i-1]) X[m++]=X[i];
        for(int i=m-1;i>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<n;i++)
        {
            int l=Bin(li[i],m);
            int r=Bin(ri[i],m);
            update(l,r,i,0,m,1);
        }
        cnt=0;
        memset(hash , false , sizeof(hash));
        query(0,m,1);
        printf("%d\n",cnt);
    }
    return 0;
}

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

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

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
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 <iostream>
#include<cstdio>
#include<cstring>
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].r<l||num[rt].l>r) 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 <iostream>
#include<cstdio>
#include<cstring>
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 <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Node
{
    int l,r,minn,maxn;
}num[4000000];
int cnt[1000000];
int min(int a,int b){if(a<b)return a;return b;}
int max(int a,int b){if(a>b)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 <iostream>
#include<cstdio>
#include<cstring>
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;i<a[cnt];i++)
        {
            if(pos[ps]>0)
                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<<k<<endl;
            ps=update(1,k);//cout<<ps<<endl;
        }
        printf("%s %d\n",name[ps],b[cnt]);
    }
    return 0;
}

14、

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

#include <stdio.h>
#include <string.h>
#include <iostream>

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 <cstdio>
#include <algorithm>
#include<cstring>
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]<num) l=mid+1;
        else r=mid-1;
    }
}
int q[maxn];
int main()
{
  //  freopen("cin.txt","r",stdin);
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        nn=0,m=1,mm;
        memset(X,0,sizeof(X));
        scanf("%d%d",&n,&mm);
        for(int i=0;i<n;i++) scanf("%d%d",&li[i],&ri[i]),X[nn++]=li[i],X[nn++]=ri[i];
        for(int i=0;i<mm;i++)scanf("%d",&q[i]),X[nn++]=q[i];
        sort(X,X+nn);
       // for(int i=0;i<nn;i++)printf("x=%d  ",X[i]);puts("");
        for(int i=1;i<nn;i++)  if(X[i]!=X[i-1]) X[m++]=X[i];
       // for(int i=m-1;i>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<m;i++)printf("x=%d  ",X[i]);puts("");
      //  printf("m=%d\n",m);
        memset(tree,0,sizeof(tree));
        for(int i=0;i<n;i++)
        {
            int l=Bin(li[i],m);
            int r=Bin(ri[i],m);
         //   printf("l=%d r=%d\n",l+1,r+1);
            update(l+1,1);
            update(r+2,-1);
          //  update(li[i],1);update(ri[i]+1,-1);
        }
        printf("Case #%d:\n",cas++);
        for(int i=0;i<mm;i++)
        {
            int qu=Bin(q[i],m);
           // printf("qu=%d\n",qu+1);
            printf("%I64d\n",query(qu+1));
        }

    }
    return 0;
}


16 扫描线

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

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值