线段树(I tree)

Codeforces Round #254 (Div. 2)E题这题说的是给了一个一段连续的区间每个区间有一种颜色然后一个彩笔从L画到R每个区间的颜色都发生了 改变然后 在L和R这部分区间里所用的颜色变成了x 然后每个区间的 色度加上abs(x-Yi) Yi 为原位置的颜色,还有一个操作就是求 L 到 R 的距离之内的所有的点和,数据 有 n<=100000 m<100000 次操作 对于每次第二种操作输出, 自然我们将一个区间的颜色如果相同自然将他们 用延迟标记 但是 会有一个问题就是在一个带有延迟标记的区间操作两次或者两次以上会然后再去求这个延迟标记的某个区间的时候我们将无法进行,这里我们稍加修改就得到了我们想要的 就是 sum=(sum[o]-sum[lc]-sum[rc)/(R-L+1)这样就得到了我们对于每个子区间的再添加两次后的个数平均值然后进行一次向下的传递就ok了 这样每个区间得到了值sum[lc]+=sum*(lc->R - lc->L + 1); sum[rc] += sum*(rc->R - rc->L +1) 然后得到向下传递的值

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn =500005;
__int64 _sum,x;
int n,m,op,y1,y2;
struct Itree{
    __int64 sumv[maxn],color[maxn];
    bool mark[maxn];
    __int64 abs(__int64 a,__int64 b){
       return (a-b)>0?(a-b):(b-a);
    }
    void build(int o, int L, int R){
         if(L == R){
              color[o]=L;
              sumv[o] =0;
              mark[o] =true;
              return ;
         }
         int M = L + ((R-L)>>1) ;
         build(o*2, L, M);
         build(o*2+1, M+1, R);
         mark[o] = false;
         sumv[o] = 0;
    }
    void pushdown(int o,int L,int R){
         int lc=o*2,rc=o*2+1;
         __int64 sum= sumv[lc]+sumv[rc];
         sum = (sumv[o]-sum)/(R-L+1);
         int M=L+((R-L)>>1);
         color[lc]=color[rc]=color[o];
         sumv[lc]+=1LL*(M-L+1)*sum;
         sumv[rc]+=1LL*(R-M)*sum;
         mark[lc]=mark[rc]=true;
    }
    void update(int o,int L, int R){
       int lc = o*2 , rc = o*2 + 1;
       if(y1<=L&&y2>=R&&mark[o]==true){
            sumv[o] += 1LL*(R-L+1)*abs(color[o],x);
            color[o]=x;
            mark[o]=true;
       }
       else{
              if(mark[o]==true) pushdown(o,L,R);
              mark[o] = false;
              int M =L+((R-L)>>1);
              if(y1<=M)update(lc,L,M);
              if(y2>M) update(rc,M+1,R);
              if(y1<=L&&y2>=R){
                    color[o]=x; mark[o]=true;
              }
              sumv[o]=sumv[lc]+sumv[rc];
       }
    }
    void query(int o, int L, int R){
           int lc =o*2,rc =o*2+1;
           if(y1<=L && y2>=R){
                _sum+=sumv[o];
           }else{
               if(mark[o]==true) pushdown(o,L,R);
               mark[o]=false;
              int M = L + ( (R-L)>>1 );
              if(y1 <= M) query(lc,L,M);
              if(y2 >  M) query(rc,M+1,R);
           }
    }
}tree;
int main()
{

     int n,m;
     scanf("%d%d",&n,&m);
     tree.build(1,1,n);
     for(int i =0; i<m; ++i){
        scanf("%d%d%d",&op,&y1,&y2);
        if(op==1){
            scanf("%I64d",&x);
            tree.update(1,1,n);
        }else{
           _sum=0;
           tree.query(1,1,n);
           printf("%I64d\n",_sum);
        }
     }
    return 0;
}

uva12299 这 题 说 的 是 给 了 一 个 数 字 数 组 要 求 找 出 某 个 区 间 内 的 最 小 值 然 后 还 有 一 个 操 作 是 循 环 的 置换 选 中 的 几 个 数 字 然 后 使 用 线 段 树 的 单 点 更 新  查询用线段树 查找

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn =100005;
int C[maxn];
int tem,y1,y2,v,_min;
struct Itree{
    int minv[maxn*4];
    void build(int o,int L,int R){
         if(L==R){
            scanf("%d",&minv[o]);
            C[L]=minv[o];
            return ;
         }
         int lc=o<<1,rc=(o<<1)|1;
         int M=L+( (R-L)>>1 );
         build(lc,L,M);
         build(rc,M+1,R);
         minv[o]=min( minv[lc], minv[rc] );
    }
    void query(int o,int L,int R){
         int lc=o<<1,rc=(o<<1)|1;
         if(y1<=L&&y2>=R){
            _min=min(_min,minv[o]);
         }
         else{
            int M=L+((R-L)>>1);
            if(y1<=M) query(lc,L,M);
            if(y2 >M) query(rc,M+1,R);
         }
    }
    void update(int o,int L,int R){
        int lc=o<<1,rc=(o<<1)|1;
        if(L==R){
             minv[o]=v;
        }
        else{
             int M=L+((R-L)>>1);
             if(tem<=M) update(lc,L,M);
             else update(rc,M+1,R);
             minv[o]=min(minv[lc],minv[rc]);
        }
    }
}tree;
char str[50];
int rt[100],len;
int worth[100];
void jud(){
    len=0;
   int L =strlen(str);
   int i=0;
   while(i<L){

      if(str[i]>=‘0‘&&str[i]<=‘9‘){
          int E = 0;
          while( str[i] >= ‘0‘ && str[i] <= ‘9‘&&i<L){
             E= E * 10 + str[i] - ‘0‘;
             ++i;
          }
          rt[len++]=E;
      }
      ++i;
   }
}
int main()
{
     int n,q;
     while( scanf("%d%d",&n,&q) == 2){
         tree.build(1,1,n);
         getchar();
         for(int i =0; i<q; ++i){
             gets(str);
             len=0;
             jud();
             if(str[0]==‘q‘){
                    y1=rt[0]; y2=rt[1];
                  _min=2147483647;
                  tree.query(1,1,n);
                  printf("%d\n",_min);
             }else{
                 for(int x =0; x<len; ++x)
                    worth[x]=C[rt[(x+1)%len]];
                 for(int x =0; x< len ;++x){
                     tem=rt[x]; v=worth[x];
                     tree.update(1,1,n);
                 }
                 for(int x =0; x<len; ++x){
                      C[rt[x]]=worth[x];
                 }
             }
         }
     }

    return 0;
}

uva1232 这题说的是给 我们要在地平线上依次建造n座建筑物.建筑物的修建按照从后往前的顺序,因此新建物可能会挡住一部分的老建筑修建完一座建筑物之后,统计他在多长的部分是最高的可以等高并把这个长度称为该建筑物的覆盖度,接下来对线段树进行稍加修改就ok了 然后记得 不要用区间去表示 将他给的点缩成 L,R-1 建树的时候同样用这样的操作

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 400005;
int L[100005],R[100005],C[100005];
int y1,y2,v,_sum;
struct Itree{
    int maxv[maxn],setv[maxn];
    void pushdown(int o){
        int lc = o<<1 , rc = (o<<1)|1;
        if(setv[o]>=0){
            setv[lc]=setv[rc]=setv[o];
            setv[o]=-1;
        }
    }
    void maintain(int o, int L, int R){
         int lc = o<<1, rc=(o<<1)|1;
         if(R>L){
             maxv[o]=max(maxv[lc], maxv[rc]);
        }
        if(setv[o]>=0){
             maxv[o]=setv[o];
        }
    }
    void query(int o,int L,int R){

         int lc =o<<1, rc =( o<<1 )|1;
          maintain(o, L, R);
          if(setv[o]>v) return;
          if(setv[o]==v){
               _sum+=min(R,y2) - max(L,y1) +1 ;
              return ;
          }
          if( y1 <= L && y2 >= R && maxv[o]<=v ){
               _sum+=R-L+1;
               setv[o]=v;
          } else {
              int M =L+((R-L)>>1);

              pushdown( o );

              if(y1<=M) query(lc,L,M);
              else maintain(lc,L,M);

              if(y2 >M) query(rc,M+1,R);
              else maintain(rc,M+1,R);
          }
          maintain(o,L,R);
    }

}tree;
int main()
{
    int n,TR,ans,t;
    scanf("%d",&t);
    while(t --){
        ans=0;
       scanf("%d",&n);
        TR=0;
        for(int i =0; i<n; ++i){
            scanf("%d%d%d",&L[i],&R[i],&C[i]);
            TR=max(R[i],TR);
        }
        tree.setv[1]=0;
        TR--;
        for(int i =0;i<n; ++i){
            _sum=0;
            v=C[i]; y1=L[i]; y2=R[i]-1;
            tree.query(1,1,TR);
            ans+=_sum;
        }
        printf("%d\n",ans);
    }
    return 0;
}

uva11525 这个题说的是给了1到K的数列 求出这个数列 的 第n 大 当然按照字典序排列, 因为 n=Si(k-i)!+Si-1(k-(i-1))!+...S0(k-k)! 经过分析我们可以得出这样的一个结论就是Si 代表的是剩下的第几大的数 用前段树去查询 每 次 找 到 相 应 的 k值

#include <iostream>
#include<cstdio>
#include <string.h>
using namespace std;
const int maxn = 50005*4;
int tem,_s,_k,S[50005],ans[50005];
struct Itree{
    int sumv[maxn];
    void build(int o,int L,int R){
       if(L==R){
           sumv[o]=1; return ;
       }
       int M=L+((R-L)>>1);
       int lc=o<<1,rc=(o<<1)|1;
       build(lc, L, M);
       build(rc, M+1, R);
       maintain(o,L,R);
    }
    void maintain(int o,int L,int R){
          int lc = o<<1, rc=(o<<1)|1;
          if(R>L){
              sumv[o] =sumv[lc]+sumv[rc];
          }
    }
    void query(int o,int L, int R){
          int lc = o<<1, rc =(o<<1)|1;
          if(L==R){
             _s=L;
             sumv[o]=0; return;
          }
          int M = L+((R-L)>>1);
          if(sumv[lc]>=_k){
             query(lc,L,M);
          }else{
              _k-=sumv[lc];
             query(rc,M+1,R);
          }
          maintain(o,L,R);
    }
}tree;
int main()
{
    int t,k;
    scanf("%d",&t);
    while(t--){
       scanf("%d",&k);
       tree.build(1,1,k);
       for(int i =0; i<k; ++i)
         scanf("%d",&S[i]);
       for(int i =0; i<k; ++i){
         _k=S[i]+1;
         tree.query(1,1,k);
         ans[i]=_s;
       }
       for(int i =0;i<k-1; ++i)
         printf("%d ",ans[i]);
       printf("%d\n",ans[k-1]);
    }
    return 0;
} 

uva11402 这题说的是 给了一排的 o1 串 有 3 种操作 1 将F L R L和R 之间的 变成1 E L R   将 L 和R 之间的变成 0  I 将 L 和 R 取 反, S L R 求 L 和 R 之间的 和  , 这样这个数 太大了有 1000000 个0 1  显然不能做  可是 他操作的区间只有 1000 个   通过离散操作区间求值 从而节省时间将  每 个 不 在 操 作 点 上 的 区 间 化 为 一 个 点 然 后 处理好值就ok了 离散了一下

#include <iostream>
#include <cstdio>
#include <string.h>
#include <set>
#include <map>
using namespace std;
const int maxn = 5005*4;
int interval[maxn][2];
int y1,y2,_sum,v,op;
struct Itree
{
     int setv[maxn],numv[maxn],ZER[maxn],ONE[maxn],addv[maxn];
     void build(int o, int L, int R)
     {
           setv[o]=-1;addv[o]=0;
           if(L==R)
           {
               ZER[o] = interval[L][1] - interval[L][0] ;
               ONE[o] = interval[L][0];
               numv[o] = interval[L][1];
               return ;
           }
           int lc=o*2,rc = o*2 + 1;
           int M =L+(R-L)/2;
           build(lc,L,M);
           build(rc,M+1,R);
           ONE[o]=ONE[lc]+ONE[rc];
           numv[o]=numv[lc]+numv[rc];
           ZER[o]=numv[o]-ONE[o];
     }
     void pushdown(int o)
     {
          int lc = o*2, rc =o*2+1;
          if( setv[o] >= 0 )
          {
              setv[lc]=setv[rc]=setv[o];
              ONE[lc] = numv[lc]*setv[o];
              ZER[lc] = numv[lc]-ONE[lc];
              ONE[rc] = numv[rc]*setv[o];
              ZER[rc] = numv[rc]-ONE[rc];
              addv[lc]=addv[rc]=0;
              setv[o]=-1;
          }
          if(addv[o]>0){
               addv[lc]=1-addv[lc];
               addv[rc]=1-addv[rc];
               swapp(ONE[lc],ZER[lc]);
               swapp(ONE[rc],ZER[rc]);
               addv[o]=0;
          }
     }
     void swapp(int &A,int &B){
          int t =A; A=B; B=t;
      }
     void update(int o, int L, int R)
     {
          int lc=o*2,rc=(o*2)+1;
          if(y1 <=L && y2 >= R)
          {
               if(op==1){
                  setv[o]=v;
                  addv[o]=0;
                  ONE[o]=setv[o]*numv[o];
                  ZER[o]=numv[o]-ONE[o];
               }else{
                  addv[o]=1-addv[o];
                  swapp(ONE[o],ZER[o]);
               }
          }else{
             int M=L+((R-L)/2);
             pushdown(o);
             if(y1<=M)update(lc,L,M);
             if(y2>M) update(rc,M+1,R);
             ONE[o]=ONE[lc]+ONE[rc];
             ZER[o]=numv[o]-ONE[o];
          }
     }
     void query(int o,int L,int R)
     {
          int lc =o*2,rc=(o*2)+1;
          if(y1<=L&&y2>=R)
          {
            _sum+= ONE[o];
          }else {
             int M =L+((R-L)/2);
             pushdown(o);
             if(y1<=M)query(lc,L,M);
             if(y2>M) query(rc,M+1,R);
          }
     }
}tree;
char SE[200],Q[1005][5];
int LZ[1005],RZ[1005],duan;
int RE[1024012],str[1024012];
int main()
{

     int T;
     scanf("%d",&T);
     for(int cas = 1; cas <=T ; ++cas)
     {
            set<int>UN;
            int len=0,QR=0,M;
            printf("Case %d:\n",cas);
            scanf("%d",&M);
            for(int i =0; i<M; ++i)
            {
                  int tim,L ;
                  scanf("%d",&tim);
                  scanf("%s",SE);
                  L=strlen(SE);
                  for( int j = 0; j < tim; ++ j )
                      for(int k =0; k<L ; ++k)
                         str[len++] = SE[k]-‘0‘;
            }
            int qz;
            scanf("%d",&qz);
            for(int i =0;i<qz ; ++ i)
            {
                 scanf("%s%d%d",Q[i],&LZ[i],&RZ[i]);
                 UN.insert(LZ[i]);
                 UN.insert(RZ[i]);
            }
            UN.insert(0);
            UN.insert(len-1);
            duan=0;
            set<int>::iterator it;
            it=UN.begin();
            int per = *it,fer;
            ++duan;
            RE[per] = duan;
            interval[duan][0]=str[per];
            interval[duan][1]=1;
            ++it;
            for(; it!=UN.end(); ++it )
            {
                   fer=*it;
                   int sT= per+1,num=0;
                   while(sT<fer)
                   {
                       if( str[sT] == 1 )
                          num++;
                       sT++;
                   }
                   if( (fer-1) > per )
                   {
                       duan++;
                       interval[duan][0]=num;
                       interval[duan][1]=fer-1-per;
                   }
                   duan++;
                   interval[duan][0] = str[fer];
                   interval[duan][1] = 1 ;
                   RE[fer]=duan;
                   per=fer;
            }
            tree.build(1,1,duan);
            for(int i =0; i<qz; ++i )
                {
                       y1 =RE[LZ[i]];
                       y2 =RE[RZ[i]];
                      if(Q[i][0]==‘F‘){
                           op=1;
                           v=1;
                           tree.update(1,1,duan);
                      }
                      else if(Q[i][0]==‘E‘){
                           op=1;
                           v=0;
                           tree.update(1,1,duan);
                      }else if( Q[i][0] == ‘I‘ ){
                           op=2;
                           tree.update(1,1,duan);
                      }else {
                          _sum=0;
                          tree.query(1,1,duan);
                          printf("Q%d: %d\n",++QR,_sum);
                      }

                }
          UN.clear();
     }

      return 0;
}

uva1455 这题说的是在一个 平面上有n个城市,初始时城市之间没有任何的双向道路相连,你的任务是一次执行以下指令.

road A B: 在城市A 和城市B 之间连接一条双向道路,保证这条道路不和其他道路在非端点处相交.

line C 询问一条 y = c 的水平线和多少个州相交.本指令中,C的小数部分保证为0.5

通过将y坐标离散化,然后得到了许多的区间 然后 通过并查集不断地去维护这个区间, 每 两 个 区间 合 并 的 时 候 就该 去 判 断 区 间 与 区 间 之 间 的 联 系 然 后 得 到 最 终 的 更 新 目 的 这 题 变 成,了成段更新单点查询  这代码中有解释

#include <iostream>
#include <cstdio>
#include <string.h>
#include <set>
#include <algorithm>
using namespace std;
const int maxn= 100005;
struct point{
     int x,y;
}Pcity[maxn];
int y1,y2,pv,zv,tem,_state,_city;
struct Itree
{
    int city[maxn*4],state[maxn*4];
    void build(int o,int L, int R)
    {
          city[o]=state[o]=0;
          if(L==R) return ;
          int M = L+((R-L)>>1);
          build(o<<1,L,M);
          build((o<<1)|1,M+1,R);
    }
    void pushdown(int o)
    {
          int lc =o<<1, rc = (o<<1)|1 ;
          city[lc] += city[o];
          city[rc] += city[o];
          state[lc]+= state[o];
          state[rc]+= state[o];
          state[o] = city[o] = 0 ;
    }
    void update(int o, int L, int R)
    {
          int lc=o<<1, rc =(o<<1)|1;
          if(y1<=L &&y2>=R)
            {
                  state[o] += zv;
                  city[o]  += pv;
            }
            else{
                  int M = L+((R-L)>>1);
                  pushdown(o);
                  if( y1 <= M ) update(lc,L,M);
                  if( y2 > M ) update(rc,M+1,R);
            }
    }
    void query(int o, int L, int R)
    {
          int lc=o<<1, rc=(o<<1)|1;
          if(R==L){
              _state = state[o];
              _city = city[o];
              return;
          }
          else {
               int M = L + ( (R-L)>>1 );
               pushdown( o );
               if(tem<=M)query( lc, L, M );
               else query( rc, M+1, R );
          }
    }
}tree;
int C[100005],DOWNm[100005],UPm[100005],per[100005],len,num[100005];
char str[20];
int RE[2000002];
int finde(int x)
{
      return per[x]==x?x:(per[x]=finde(per[x]));
}
void upoperator(int Lloc, int Rloc, int pvw, int zvw)
{
        y1 = RE[Lloc]+1; y2 =RE[Rloc];
        pv = pvw; zv = zvw;
        tree.update(1,1,len);
}
void intf(int p1, int p2)
{
       int DOWN =min(DOWNm[p1],DOWNm[p2]) , UP= max(UPm[p1],UPm[p2]);
       per[p1]=p2;
       num[p2]+=num[p1];
       DOWNm[p2]=DOWN; UPm[p2]=UP;
}
void OneToSet(int p1, int p2)
{
       if( DOWNm[p1] >= DOWNm[p2] && DOWNm[p1] <= UPm[p2] )
        {//p1点在 p2集合 区间内
            upoperator( DOWNm[p2],UPm[p2],num[p1],0 );
            intf(p1,p2);
             return ;
        }
        if( DOWNm[p1] > UPm[p2] )
        {// p1这个点在 p2集合的上面
            upoperator(UPm[p2],DOWNm[p1],num[p2]+num[p1],1);
            upoperator(DOWNm[p2],UPm[p2],num[p1],0);
            intf(p1,p2);
            return;
        }
        if( DOWNm[p1] < UPm[p2] )
        {// p1 这个点在 p2集合的 下面
            upoperator( DOWNm[p1], DOWNm[p2], num[p1]+num[p2], 1);
            upoperator( DOWNm[p2], UPm[p2],num[p1],0);
            intf(p1,p2);
            return ;
        }
}
void intersect(int p1, int p2)
{
      if(UPm[p1]-UPm[p2]>0)
       upoperator(UPm[p2], UPm[p1], num[p2],0);
      if(UPm[p2]-DOWNm[p1]>0)
       upoperator(DOWNm[p1],UPm[p2],0,-1);
      if(DOWNm[p1]-DOWNm[p2]>0)
        upoperator(DOWNm[p2] , DOWNm[p1], num[p1],0);
      intf(p1,p2);
}
void SetToSet(int p1, int p2)
{
       if( DOWNm[p1] > UPm[p2] )
        {//相离 p1 在上面
              upoperator( DOWNm[p1], UPm[p1], num[p2], 0);
              upoperator( UPm[p2], DOWNm[p1], num[p2]+num[p1], 1);
              upoperator( DOWNm[p2], UPm[p2], num[p1], 0);
              intf(p1,p2); return ;
        }
       if( DOWNm[p2] > UPm[p1] )
        {//相离 p2 在上面
               upoperator(DOWNm[p2], UPm[p2], num[p1], 0);
               upoperator(UPm[p1], DOWNm[p2], num[p1]+num[p2],1);
               upoperator(DOWNm[p1], UPm[p1], num[p2], 0);
               intf(p1,p2);
                  return ;
        }
        if( DOWNm[p1] >= DOWNm[p2] && UPm[p1] <= UPm[p2] )
        {//包含
              if(UPm[p2] -UPm[p1]>0)
                    upoperator(UPm[p1], UPm[p2] , num[p1],0);
              if(UPm[p1]-DOWNm[p1]>0)
                    upoperator(DOWNm[p1],UPm[p1],0,-1);
              if(DOWNm[p1]-DOWNm[p2]>0)
                    upoperator(DOWNm[p2], DOWNm[p1], num[p1],0);
              intf(p1,p2); return ;
        }
        if( UPm[p1]>UPm[p2])  // 相交
        intersect(p1,p2); // p1 在p2 的上面
        else intersect(p2,p1); // p1 在p2 的下面
}
void solve1(int p1, int p2)
{
    int fp1 =finde(p1);
    int fp2 =finde(p2);
    if(fp1 == fp2) return;
    if( DOWNm[fp1] == UPm[fp1]&& DOWNm[fp2] == UPm[fp2] && DOWNm[fp1] == DOWNm[fp2] )
    { // fp1 和 fp2 都是各自在同一行的点 或者集合 但是 他们 在同一行
           intf(fp1,fp2);
           return ;
    }
    if(DOWNm[fp1]==UPm[fp1] && DOWNm[fp2]==UPm[fp2] && DOWNm[fp1] != DOWNm[fp2])
    {// fp1 和 fp2 都是各自在同一行的点 或者集合 但是 他们 不在同一行
           int DOWN= min(DOWNm[fp1],DOWNm[fp2]), UP =max(UPm[fp1],UPm[fp2]);
           upoperator( DOWN, UP, num[fp2]+num[fp1], 1 );
           intf(fp1,fp2);return ;
    }
    if( DOWNm[fp1] == UPm[fp1] && DOWNm[fp2] != UPm[fp2] )
    {// fp1 是一个点 fp2 是一个集合
            OneToSet(fp1,fp2);     return ;
    }
    if(DOWNm[fp1] != UPm[fp1] && DOWNm[fp2] == UPm[fp2])
    {// fp2 是一个点 fp1 是一个集合
            OneToSet(fp2,fp1);    return ;
    }
     int R1 = UPm[fp1] - DOWNm[fp1],R2=UPm[fp2] - DOWNm[fp2]; // 剩下的只可能是两个集合 计算两个集合的大小
     if(R1<=R2)
        SetToSet(fp1,fp2);  // fp1 的集合小于 fp2 的集合
     else SetToSet(fp2,fp1); // fp2 的集合小于 fp1 的集合
}
void solve2(int h)
{
    int t = lower_bound(C,C+len+1,h) - C;
    tem=t;
    tree.query(1,1,len);
    printf("%d %d\n",_state,_city);
}
int main()
{
     int T,n;
     scanf("%d",&T);
     for(int cas =1; cas <=T ; ++cas)
     {
            set<int> UN;
            scanf("%d",&n);
            for(int i =0; i<n ;++i)
            {
               scanf("%d%d",&Pcity[i].x,&Pcity[i].y);
               Pcity[i].y*=2;
               per[i]=i;
               UPm[i] = DOWNm[i] = Pcity[i].y;
               num[i]=1;
               UN.insert(Pcity[i].y);
            }
            UN.insert(0);UN.insert(1000000*2);
            len=0;
            for(set<int>::iterator it = UN.begin(); it!=UN.end() ; ++it)
                {
                       int to = *it;
                       RE[to] =len;
                       C[ len ++ ] = to;
                }
                len--;
              tree.build(1,1,len);
             memset(tree.city,0,sizeof(tree.city));
             memset(tree.state,0,sizeof(tree.state));
            int m;
            scanf("%d",&m);
            for(int i =0; i<m; ++i)
            {
                 scanf("%s",str);
                 if(str[0]==‘r‘)
                    {
                         int p1,p2;
                         scanf("%d%d",&p1,&p2);
                         solve1(p1,p2);
                    }
                 else
                    {
                         double red;
                         scanf("%lf",&red);
                         solve2(red*2);
                    }
            }
            UN.clear();
     }
     return 0;
}

446C DZY Loves Fibonacci Numbers 这题说的是给了一组数从1编号到n 每个数都有初值, 有两种操作分别是1 l r 将 l和r 区间内的数 相对应的每个位置加上斐波那契f[1] 到f[r-l+1],通过数学方法他们证出斐波那契的通项

   然后发现同余 然后这个 然后接下来的我就知道了 通过求逆得到

这个 可以用线段树来解决 因为我们知道等比数列相加和仍然是等比 然后通过这个每个线段树都有一个标记 标记的是 该数列的第一项然后 向下更新的时候就是 让 per[lc]+=per[o] per[rc]=per[lc]*q^(M+1-L) 然后得到了正解  虽然和其他的原理相同 还是把他敲了一遍 如果是自己想出来的 那就更有成就感了

#include <cstdio>
#include <string.h>
#include <iostream>
using namespace std;
const __int64 mod = 1000000009;
const int maxn=300005;
__int64 q1=691504013,q2=308495997,req1=308495996,req2=691504012,Y=276601605;
__int64 F[maxn],A[maxn];
__int64 pow_2(int n,__int64 q)
{
      __int64 a=q;
      __int64 ans=1;
      while(n>0)
      {
          if(n&1) ans=(ans*a)%mod;
          a=(a*a)%mod;
          n/=2;
      }
      return ans;
}
__int64 _sum;
int y1,y2;
struct Itree
{
     __int64 per[maxn*4],fer[maxn*4],sumv[maxn*4],falg[maxn*4],addv[maxn*4];
     void pushdown(int o,int L,int R)
     {
           int lc=o*2,rc=o*2+1;
           int M = (L+R)/2;
           if(falg[o])
           {
               if(per[o]!=0){
                   per[lc]=( per[lc]+per[o])%mod;
                   per[rc]=( per[rc]+per[o]*F[M+1-L])%mod;
                   per[o]=0;
                }
              if(fer[o]!=0){
               fer[lc] = (fer[lc]+fer[o])%mod;
               fer[rc] = (fer[rc]+fer[o]*A[M+1-L])%mod;
               fer[o]=0;
               }
               falg[o]=false;
               falg[lc]=true;
               falg[rc]=true;
           }
     }
     void maintain(int o,int L, int R)
     {
          int lc=o*2,rc =o*2+1;
          sumv[o]=0;
           if(falg[o])
           {
             __int64 qn1=F[R-L+1];
             __int64 qn2=A[R-L+1];
             __int64 t1 =( ( ( ( ( 1-qn1+ mod )%mod ) *req1 )%mod) *per[o] )%mod;
             __int64 t2 =( ( ( ( ( 1-qn2+ mod )%mod ) *req2 )%mod) *fer[o] )%mod;
             sumv[o]=( ( ( (t1-t2)%mod + mod )%mod ) * Y )%mod;
           }
           sumv[ o ] += addv[ o ] ;
           if( L<R ){
              sumv[o] += sumv[lc] + sumv[rc] ;
           }
     }
     void update(int o,int L,int R)
     {
           int lc=o*2,rc=o*2+1;
           if(y1<=L&&y2>=R){
            per[o] = (per[o]+(q1*F[L-y1])%mod)%mod;
            fer[o] = (fer[o]+(q2*A[L-y1])%mod)%mod;
            falg[o]=true;
           }else{
               int M =(L+R)/2;
               pushdown(o,L,R);
               if(y1<=M)update(lc,L,M);
               else maintain(lc,L,M);
               if(y2>M)update(rc,M+1,R);
               else maintain(rc,M+1,R);
           }
           maintain(o,L,R);
     }
     void query(int o,int L,int R)
     {
          int lc =o*2, rc =o*2+1;
          if(y1<=L&&y2>=R){
              _sum=(_sum+sumv[o])%mod;
          }else{
              int M=(L+R)/2;
              pushdown(o,L,R);
              maintain(lc,L,M);
              maintain(rc,M+1,R);
              if(y1<=M)query(lc,L,M);
              if(y2>M)query(rc,M+1,R);
          }

     }
     void build(int o, int L, int R)
     {
         addv[o]=per[o]=fer[o]=0;
          falg[o]=false;
          if(L==R){
             scanf("%I64d",&sumv[o]);
             addv[o]=sumv[o];
             return;
          }
          int lc =o*2,rc =o*2+1;
          int M = (L+R)/2;
          build(lc,L,M);
          build(rc,M+1,R);
          sumv[o]=sumv[lc]+sumv[rc];
    }
}tree;
void gcd(__int64 a,__int64 b,__int64 &g,__int64 &x,__int64 &y)
{
       if(b==0){
           g=a ; x=1; y=0;
       }else{
           gcd(b,a%b,g,y,x); y-=x*(a/b);
       }
}
__int64 exd(__int64 a,__int64 b)
{
       __int64 x,y,g;
       gcd(a,b,g,x,y);
       return g==1?(x+b)%b:-1;
}
__int64 C[100],R[100];
int main()
{

      int n,m;
      A[0]=F[0]=1;
      for(int i =1 ; i<=300000; ++i)
      {
          F[i]=(F[i-1]*q1)%mod;
          A[i]=(A[i-1]*q2)%mod;
      }
      scanf("%d%d",&n,&m);
      tree.build(1,1,n);
      for(int i =0; i<m; ++i)
        {
              int c;
              scanf("%d%d%d",&c,&y1,&y2);
              if(c==1) tree.update(1,1,n);
              else {
                  _sum=0;
                  tree.query(1,1,n);
                  printf("%I64d\n",(_sum)%mod);
              }
        }
      return 0;
}

时间: 2024-11-08 09:31:23

线段树(I tree)的相关文章

线段树(segment tree)

1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即"子数组"),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 使用线段树可以

线段树 Interval Tree

一.线段树 线段树既是线段也是树,并且是一棵二叉树,每个结点是一条线段,每条线段的左右儿子线段分别是该线段的左半和右半区间,递归定义之后就是一棵线段树. 例题:给定N条线段,{[2, 5], [4, 6], [0, 7]}, M个点{2, 4, 7},判断每个点分别在几条线段出现过? 1.构建线段树 2.处理线段 三条线段分割之后 3.查询 对于每一个值我们就可以开始遍历这一颗线段树,加上对于结点的count字段便是在线段中出现的次数 比如对于4,首先遍历[0, 7],次数 = 0+1=1:4在

线段树(Segment Tree)(转)

原文链接:线段树(Segment Tree) 1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即

【数据结构】线段树(interval tree)

线段树(interval tree),也叫区间树.也是一种二叉搜索树,同一般的BST不同之处在于:线段树的每一个结点包含的是一个区间而不是一个数.具体的描述如下: 从图上可以看出,线段树的每一个结点都是一个线段(区间),子节点是对父结点的进一步分划,每个子节点的长度都是父节点的二分,每个叶子结点就是一个元素. 每个节点可以用一个变量hit_count来计算在每一段的命中率,这样可以用来统计此线段线段或者区间内的命中率. 区间树主要用在一些跟统计和分部相关的计算中,可以快速找到相应的数据.

hdu4521 小明系列问题——小明序列(LIS变种 (线段树+单点更新解法))

链接: huangjing 题目:中文题目 思路: 这个题目如果去掉那个距离大于d的条件,那么必然是一个普通的LIS,但是加上那个条件后就变得复杂了.用dp的解法没有看懂,我用的线段树的解法...就是采用延迟更新的做法,用为距离要大于d啊,所以我们在循环到第i的时候,就对(i-d-1)这个点进行更新,因为如果在(i-d-1)这个点更新了,会对后面的造成影响,然后线段树的tree[]数组存的是以i结尾的最长lis,那么每次询问的时候就找最大的tree[]就可以了... 代码: 小明系列问题--小明

【POJ 2528】Mayor’s posters(线段树+离散化)

题目 给定每张海报的覆盖区间,按顺序覆盖后,最后有几张海报没有被其他海报完全覆盖.离散化处理完区间端点,排序后再给相差大于1的相邻端点之间再加一个点,再排序.线段树,tree[i]表示节点i对应区间是哪张海报,如果是-1代表对应区间不是一张海报(0或多张).每贴一张海报,就用二分查找出覆盖的起点和终点对应的离散后的下标,然后更新区间.线段树的区间更新可以加上懒惰标记(或延迟标记,但是这题可以不用另外标记. #include<cstdio> #include<cstring> #in

线段树(一)

问题: 先抛出一个问题,坐标轴上有若干线段,现在给定若干个点,对于每个点,求出包含点的线段的数量 如果用常规的解法,时间复杂度是O(mn),空间复杂度是O(m + n) 能不能降低一下时间复杂度呢?答案是肯定的,这些线段里有大量相交或者覆盖的线段,而上面的解法显然没有利用这些信息,导致时间复杂度较高,现在我们引入 一个数据结构,线段树(Segment Tree),从Wikipedia抄过来定义如下: In computer science, a segment tree is a tree da

线段树之入门篇

线段树(interval tree) 是把区间逐次二分得到的一树状结构,它反映了包括归并排序在内的很多分治算法的问题求解方式. 上图是一棵典型的线段树,它对区间[1,10]进行分割,直到单个点.这棵树的特点 是: 1. 每一层都是区间[a, b]的一个划分,记 L = b - a 2. 一共有log2L层 3. 给定一个点p,从根到叶子p上的所有区间都包含点p,且其他区间都不包含点p. 4. 给定一个区间[l; r],可以把它分解为不超过2log2 L条不相交线段的并. 其中第四点并不是很显然,

《数据结构》线段树入门(一)

今天介绍一种非常特殊的数据结构——线段树 首先提出一个问题: 给你n个数,有两种操作: 1:给第i个数的值增加X 2:询问区间[a,b]的总和是什么? 输入描述 输入文件第一行为一个整数n,接下来是n行n个整数,表示格子中原来的整数.接下一个正整数q,再接 下来有q行,表示q个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给 位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和. 样例输入 4 7 6 3 5 2 1 1