<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      書山有徑勤為路>>>>>>>>

      <<<<<<<<學海無涯苦作舟!

      線段樹專題

      1.hud 1166 http://acm.hdu.edu.cn/showproblem.php?pid=1166    敵兵布陣

        本題目涉及到了區間操作和點操作兩種操作。

        區間操作(區間和):我們采用了遞推的方法來建樹,建好了葉子結點之后,我們再回溯來建整個區間。(這個操作是關鍵)

        點操作:點操作必然涉及到區間的改動,我們判定,只要這個點在一個區間上,那么我們就對這個區間操作。

      View Code
      #include "iostream"
      #include "string"
      #include "algorithm"
      using namespace std;
      #define maxn 50005
      int len, peo[maxn], ans;
      typedef struct node
      {
          int l, r, m;
          int s;
      }node;
      node t[maxn*4];
      void build(int ll, int le, int ri)
      {
          t[ll].l = le;
          t[ll].r = ri;
          t[ll].m = (le+ri)>>1;
          if(le==ri) t[ll].s = peo[le];
          else
          {
              build(ll<<1, le, t[ll].m);
              build(ll<<1|1, t[ll].m+1, ri);
              t[ll].s = t[ll<<1].s + t[ll<<1|1].s;
          }
      }
      void query(int ll, int le, int ri)
      {
          if(le<=t[ll].l && ri>=t[ll].r) ans+=t[ll].s;
          else
          {
              if(le>t[ll].m) query(ll<<1|1, le, ri);
              else if(ri<=t[ll].m) query(ll<<1, le, ri);
              else 
              {
                  query(ll<<1, le, t[ll].m);
                  query(ll<<1|1, t[ll].m+1, ri);
              }
          }
      }
      void add(int ll, int p, int v)
      {
          if(p>=t[ll].l && p<=t[ll].r) t[ll].s += v;
          if(t[ll].l==p && t[ll].r==p) return;
          if(p>t[ll].m) add(ll<<1|1, p, v);
          else if(p<=t[ll].m) add(ll<<1, p, v);
      }
      void sub(int ll, int p, int v)
      {
          if(p>=t[ll].l && p<=t[ll].r) t[ll].s -= v;
          if(t[ll].l==p && t[ll].r==p) return;
          if(p>t[ll].m) sub(ll<<1|1, p, v);
          else if(p<=t[ll].m) sub(ll<<1, p, v);
      }
      int main()
      {
          int i, j, C, le, ri;
          char op[10];
          scanf("%d", &C);
          for(i=1; i<=C; i++)
          {
              printf("Case %d:\n", i);
              scanf("%d", &len);
              for(j=1; j<=len; j++) scanf("%d", peo+j);
              
              build(1, 1, len);
      
              while(scanf("%s", op)!=EOF)
              {
                  if(strcmp(op, "End")==0) break;
                  scanf("%d%d", &le, &ri);
                  if(strcmp(op, "Query")==0)
                  {
                      ans = 0;
                      query(1, le, ri);
                      printf("%d\n", ans);
                  }
                  else if(strcmp(op, "Add")==0)
                  {
                      add(1, le, ri);
                  }
                  else if(strcmp(op, "Sub")==0)
                  {
                      sub(1, le, ri);
                  }
              }
          }
          return 0;
      }

       

      2.hdu 1754 http://acm.hdu.edu.cn/showproblem.php?pid=1754     I hate it

        本題目涉及到了區間操作和點操作兩種操作。

        區間操作(區間最值):平常的建樹。

        點操作:我們每向區間插入一個點就和當前區間的最大值比較一下,如果大于最大值,則更新。(這個操作是關鍵)

      View Code
      #include "iostream"
      #include "string"
      #include "cstdio"
      #include "cstring"
      #include "algorithm"
      using namespace std;
      #define maxn 200005
      typedef struct node
      {
          int l, r, m, ma;
      }node;
      int ans;
      node t[maxn<<2];
      void Build(int ll, int l, int r)
      {
          t[ll].ma=-1;
          t[ll].l=l;
          t[ll].r=r;
          t[ll].m=(l+r)>>1;
          if(l!=r)
          {
              Build(ll<<1, l, t[ll].m);
              Build(ll<<1|1, t[ll].m+1, r);
          }
      }
      void Insert(int ll, int p, int v)
      {
          if(p>=t[ll].l && p<=t[ll].r && t[ll].ma<v) t[ll].ma=v;
          if(p==t[ll].l && p==t[ll].r) return;
          if(p<=t[ll].m) Insert(ll<<1, p, v);
          else if(p>t[ll].m) Insert(ll<<1|1, p, v);
      }
      int Find(int ll, int l, int r)
      {
          if(l==t[ll].l && t[ll].r==r) return t[ll].ma; 
          if(r<=t[ll].m) Find(ll<<1, l, r);
          else if(l>t[ll].m) Find(ll<<1|1, l, r);
          else
          {
              int a=Find(ll<<1, l, t[ll].m);
              int b=Find(ll<<1|1, t[ll].m+1, r);
              return a>b?a:b;
          }
      }
      int main()
      {
          int n, op, i, j, v, l, r;
          char opp[10];
          while(scanf("%d%d", &n, &op)!=EOF)
          {
              Build(1, 1, n);
              for(i=1; i<=n; i++)
              {
                  scanf("%d", &v);
                  Insert(1, i, v);
              }
              for(i=0; i<op; i++)
              {
                  scanf("%s%d%d", opp, &l, &r);
                  if(strcmp(opp, "Q")==0) 
                  {
                      
                      printf("%d\n", Find(1, l, r));
                  }
                  else if(strcmp(opp, "U")==0)
                  {
                      Insert(1, l, r);
                  }
              }
          }
      }

       

      3.hdu 1698http://acm.hdu.edu.cn/showproblem.php?pid=1698    Just a hook

        本題只涉及到了區間操作。

        區間操作(全區間鍵值的改變):在維護更新的時候我們將無用的區間屏蔽掉,這樣就可以大大提高時間效率。如何屏蔽?這個是關鍵。

      View Code
      #include "iostream"
      #include "string"
      #include "cstdio"
      #include "cstring"
      #include "algorithm"
      using namespace std;
      #define maxn 100005
      #define L(x) (x<<1)
      #define R(x) (x<<1|1)
      typedef struct node
      {
          int l, r, z;
      }node;
      node t[maxn<<2];
      void Build(int ll, int l, int r)
      {
          t[ll].l=l;
          t[ll].r=r;
          t[ll].z=1;
          if(l<r)
          {
              int m=(t[ll].l+t[ll].r)>>1;
              Build(L(ll), l, m);
              Build(R(ll), m+1, r);
          }
      }
      void Update(int ll, int l, int r, int z)
      {
          if(l==t[ll].l && t[ll].r==r) 
          {
              t[ll].z=z;//更新
              return;
          }
          if(t[ll].z>0)//只要不是剛好的區間,我們就往下更新,同時將這一層的區間屏蔽掉,說具體點就是t[ll].z=-1
          {
              t[R(ll)].z = t[ll].z;
              t[L(ll)].z = t[ll].z;
              t[ll].z=-1;
          }
          if(t[ll].l==t[ll].r) return;
          int m=(t[ll].l+t[ll].r)>>1;
          if(r<=m) Update(L(ll), l, r, z);
          else if(l>m) Update(R(ll), l, r, z);
          else 
          {
              Update(L(ll), l, m, z);
              Update(R(ll), m+1, r, z);
          }
      }
      int Query(int ll, int l, int r)
      {
          if(t[ll].z>0) return (t[ll].r-t[ll].l+1)*t[ll].z;
          int m=(t[ll].l+t[ll].r)>>1;
          if(r<=m) return Query(L(ll), l, r);
          else if(l>m) return Query(R(ll), l, r);
          else return Query(L(ll), l, m)+Query(R(ll), m+1, r);
      }
      int main()
      {
          int c, n, op, i, l, r, z, j, ans;
          scanf("%d", &c);
          for(i=1; i<=c; i++)
          {
              scanf("%d%d", &n, &op);
              Build(1, 1, n);
              for(j=0; j<op; j++)
              {
                  scanf("%d%d%d", &l, &r, &z);
                  Update(1, l, r, z);
              }
              ans=Query(1, 1, n);
              printf("Case %d: The total value of the hook is %d.\n", i, ans);
          }
      }

       

      4.hdu 1394http://acm.hdu.edu.cn/showproblem.php?pid=1394    Minimum Inversion Number

      本題是一種類型的題目——逆序數的求法。

      本題涉及到了區間操作。

      但是本題的區間操作有一定的講究,也就是一邊插入一邊查找。不然等插入完了再來查找就不知道是在它前面還是后面出現的了。

      其它的就和平常的線段樹一樣了。

      View Code
      #include "iostream"
      #include "string"
      #include "cstring"
      #include "algorithm"
      #include "cstdio"
      using namespace std;
      #define maxn 5005
      #define L(x) (x<<1)
      #define R(x) (x<<1|1)
      typedef struct segtree
      {
          int l, r, s;
      }segtree;
      segtree t[maxn<<2];
      int s[maxn];
      void Build(int ll, int l, int r)
      {
          t[ll].l=l;
          t[ll].r=r;
          t[ll].s=0;
          if(l<r)
          {
              int m=(l+r)>>1;
              Build(L(ll), l, m);
              Build(R(ll), m+1, r);
          }
      }
      int Query(int ll, int l, int r)
      {
          if(t[ll].l==l && t[ll].r==r) return t[ll].s;
          int m=(t[ll].l+t[ll].r)>>1;
          if(r<=m) return Query(L(ll), l, r);
          else if(l>m) return Query(R(ll), l, r);
          else return Query(L(ll), l, m)+Query(R(ll), m+1, r);
      }
      void Update(int ll, int k)
      {
          t[ll].s++;
          if(t[ll].l==t[ll].r) return;
          int m=(t[ll].l+t[ll].r)>>1;
          if(k<=m) Update(L(ll), k);
          else Update(R(ll), k);
      }
      int main()
      {
          int n, i, t, ans;
          while(scanf("%d", &n)!=EOF)
          {
              ans=0;
              Build(1, 0, n-1);
              for(i=0; i<n; i++)//我們來求一下“輸入順序時”的逆序對數
              {
                  scanf("%d", &s[i]);
                  ans+=Query(1, s[i], n-1);//在s[i]~n-1這個區間中有多少個數是在s[i]之前出現的,那么對于這個數而言就有多少個逆序對數,不是嗎?好好想想……
                  Update(1, s[i]);
              }
              t=ans;
              for(i=0; i<n-1; i++)
              {
                  t=t+(n-1-s[i])-s[i];
                  if(ans>t) ans=t;
              }
              printf("%d\n", ans);
          }
          return 0;
      }

       

      5. hdu 2492http://acm.hdu.edu.cn/showproblem.php?pid=2492    Ping pong

      本題也是一道逆序數的題目。只不為要求兩種逆序都要算出來。也就是說A>B>C和A<B<C兩種情況。

      其實仔細想想本題我們可以得到一個這樣的結論。

      如果完全按照題目的描述來想算法,我們是很容易進入誤區的,

      但是,如果我們將題目的意思也取反來看一下,當然這個取反和原題意是等價的,就很容易知道是什么樣的題目了。

      View Code
      #include "iostream"
      #include "string"
      #include "cstring"
      #include "algorithm"
      #include "cstdio"
      using namespace std;
      #define maxn 20010
      #define maxs 100010
      #define L(x) (x<<1)
      #define R(x) (x<<1|1)
      typedef struct segtree
      {
          int l, r, s;
      }segtree;
      segtree t[maxs<<2];
      int s[maxn];
      void Build(int f, int l, int r)
      {
          t[f].l=l;
          t[f].r=r;
          t[f].s=0;
          if(l<r)
          {
              int m=(l+r)>>1;
              Build(L(f), l, m);
              Build(R(f), m+1, r);
          }
      }
      int Query(int f, int l, int r)
      {
          if(t[f].l==l && t[f].r==r) return t[f].s;
          int m=(t[f].l+t[f].r)>>1;
          if(r<=m) return Query(L(f), l, r);
          else if(l>m) return Query(R(f), l, r);
          else return Query(L(f), l, m)+Query(R(f), m+1, r);
      }
      void Update(int f, int k)
      {
          t[f].s++;
          if(t[f].l==t[f].r) return;
          int m=(t[f].l+t[f].r)>>1;
          if(k<=m) Update(L(f), k);
          else Update(R(f), k);
      }
      int main()
      {
          int n, i, T, k;
          long long fs[maxn], fb[maxn], ss[maxn], sb[maxn]; 
          scanf("%d", &T);
          for(k=0; k<T; k++)
          {
              scanf("%d", &n);
              memset(fs, 0, sizeof fs);
              memset(fb, 0, sizeof fb);
              memset(ss, 0, sizeof ss);
              memset(sb, 0, sizeof sb);
              Build(1, 1, maxs);
              for(i=0; i<n; i++)//我們來求一下“輸入順序時”的逆序對數
              {
                  scanf("%d", &s[i]);
                  fb[i]=Query(1, s[i]+1, maxs);//big
                  if(s[i]==1)
                  {
                      Update(1, s[i]);
                      continue;
                  }
                  fs[i]=Query(1, 1, s[i]-1);//在s[i]~n-1這個區間中有多少個數是在s[i]之前出現的,那么對于這個數而言就有多少個逆序對數,不是嗎?好好想想……
                  Update(1, s[i]); 
              }
              Build(1, 1, maxs);
              for(i=n-1; i>=0; i--)
              {
                  sb[i]=Query(1, s[i]+1, maxs);
                  if(s[i]==1)
                  {
                      Update(1, s[i]);
                      continue;
                  }
                  ss[i]=Query(1, 1, s[i]-1);//small
                  Update(1, s[i]);
              }
              long long ans=0;
              for(i=1; i<n-1; i++)
              {
                  ans+=fs[i]*sb[i];
                  ans+=fb[i]*ss[i];
              }
              printf("%I64d\n", ans);
          }
          return 0;
      }

       

       6. hdu 3308http://acm.hdu.edu.cn/showproblem.php?pid=3308    LCIS

      本題是一種類型的題目,解法有一定的套路。也就是lm,rm,m,len,lv,rv等等,具體是什么含義,看看代碼就知道了。

      本題涉及到了區間操作和點的操作。

      區間操作,這個比較麻煩,因為沒有記錄左右邊界,所以要小心,這只是一個不起眼的小難題。

      區間的操作,難就難在up函數,和query函數上,這兩個一定要看懂。其它的就好說了。

      點操作一般,就是平時的操作。

      View Code
      #include "iostream"
      #include "string"
      #include "cstdio"
      #include "cstring"
      #include "algorithm"
      using namespace std;
      #define L(x) (x<<1)
      #define R(x) (x<<1|1)
      #define maxn 100005
      typedef struct node
      {
          int lm, rm, m;
          int lv, rv, len;
      }node;//我們并沒有記錄l, r
      node t[maxn<<2];
      void Up(node &f, node &l, node &r)
      {
          f.lv = l.lv;
          f.rv = r.rv;
          if(l.rv<r.lv)//是遞增的
          {
              f.lm=(l.lm==l.len?l.lm+r.lm:l.lm);//左邊的最值就是它的區間長度那么……否則……
              f.rm=(r.rm==r.len?r.rm+l.rm:r.rm);//右邊的最值就是它的區間長度那么……否則……
              f.m=max(max(f.lm, f.rm), l.rm+r.lm);//l.rm+r.lm表示不包含左右端點的值
              f.m=max(max(l.m, r.m), f.m);
          }
          else//如果不是遞增的
          {
              f.lm=l.lm;
              f.rm=r.rm;
              f.m=max(l.m, r.m);
          }
      }
      void Build(int f, int l, int r)
      {
          t[f].len=r-l+1;
          if(l==r)
          {
              scanf("%d", &t[f].lv);
              t[f].rv = t[f].lv;
              t[f].lm = t[f].rm = t[f].m = 1;
              return;
          }
          int m=(l+r)>>1;
          Build(L(f), l, m);
          Build(R(f), m+1, r);
          //當建樹完成的時候我們要進行統計運算,也就是向上計算
          Up(t[f], t[L(f)], t[R(f)]);
      }
      void Update(int f, int l, int r, int p, int v)//我們只需要更新它的lv, rv就可以了
      {
          if(l==r)
          {
              t[f].lv = t[f].rv = v;
              return;
          }
          int m=(l+r)>>1;
          if(p<=m) Update(L(f), l, m, p, v);//
          else Update(R(f), m+1, r, p, v);//我們的目的是更新葉子結點,所以不需要更新區間
          //當修改完成的時候我們要進行統計運算,也就是向上計算
          Up(t[f], t[L(f)], t[R(f)]);
      }
      node Query(int f, int l, int r, int &L, int &R)
      {
          if(L<=l && r<=R) return t[f];
          int m=(l+r)>>1;
          node t1, t2;
          t1.len=t2.len=0;
          if(L<=m) t1=Query(L(f), l, m, L, R);//往左可走,就走
          if(R>m) t2=Query(R(f), m+1, r, L, R);//往右可走,就走
          if(t1.len && t2.len)//都找到了,從兩邊找到了
          {
              node tmp;
              Up(tmp, t1, t2);
              tmp.len=t1.len+t2.len;//哦哦,有可能多次更新,所以不能大意哦!!!
              return tmp;
          }
          if(t1.len) return t1;
          return t2;
      }
      int main()
      {
          int T;
          scanf("%d",&T);
          while(T--)
          {
              int n,m,x,y;
              node te;
              char c;
              scanf("%d%d",&n,&m);
              n--;
              Build(1, 0,n);
              getchar();
              while(m--)
              {
                  getchar();
                  scanf("%c%d%d",&c,&x,&y);
                  if(c=='Q')
                  {
                      te=Query(1,0,n,x,y);
                      printf("%d\n",te.m);
                  }
                  else Update(1, 0, n, x, y);
              }
          }
          return 0;
      }

       

      7.hdu 4046http://acm.hdu.edu.cn/showproblem.php?pid=4046    Panda

      本題就是一道簡單的線段樹題目。

      但是難就難在只有當我們經過一定的轉化之后,才可以用線段樹來做,轉化的這個過程是比較困難的。

      這就是本題的難點所在。轉化 轉化 轉化 轉化 再轉化

      View Code
      #include "iostream"
      #include "string"
      #include "cstdio"
      #include "cstring"
      #include "algorithm"
      using namespace std;
      #define L(x) (x<<1)
      #define R(x) (x<<1|1)
      #define maxn 50010
      typedef struct node
      {
          int l, r, s;
      }node;
      node t[maxn<<2];
      char str[maxn];
      int a[maxn];
      void build(int f, int l, int r)
      {
          t[f].l = l;
          t[f].r = r;
          if(l==r)
          {
              t[f].s=a[l];
              return;
          }
          int m=(l+r)>>1;
          build(L(f), l, m);
          build(R(f), m+1, r);
          t[f].s=t[L(f)].s+t[R(f)].s;
      }
      void update(int f, int l, int r, int p, int v)
      {
          if(l==r)
          {
              t[f].s=v;
              return;
          }
          int m=(l+r)>>1;
          if(p<=m) update(L(f), l, m, p, v);
          else update(R(f), m+1, r, p, v);
          t[f].s=t[L(f)].s+t[R(f)].s;
      }
      int Query(int f, int l, int r, int L, int R)
      {
          if(L<=l && r<=R) return t[f].s;
          int m=(l+r)>>1;
          int ret=0;
          if(L<=m) ret += Query(L(f), l, m, L, R);
          if(R>m) ret += Query(R(f), m+1, r, L, R);
          return ret;
      }
      int main()
      {
          int cas,T=0,n,m,r,l,c;  
          char st;  
          scanf("%d",&cas);  
          while(cas--)  
          {  
              scanf("%d %d",&n,&m);  
              scanf("%s",str);  
              memset(a,0,sizeof(a));  
              printf("Case %d:\n",++T);  
              for(int i=2;i<n;i++)//標記以該下標結尾的長度為3的子串是否符合要求  
              {  
                  if(str[i]!='w')  
                      a[i]=0;  
                  else if(str[i-1]=='b'&&str[i-2]=='w')  
                      a[i]=1;  
              }  
              build(1,0,n);  
              while(m--)  
              {  
                  scanf("%d",&c);  
                  if(c==0)  
                  {  
                      scanf("%d %d",&l,&r);  
                      l+=2;  
                      if(l>r) printf("0\n");  
                      else printf("%d\n",Query(1,0,n,l,r));  
                  }  
                  else  
                  {  
                      scanf("%d %c",&l,&st);  
                      if(str[l]==st)//若要就該的字符跟原先相同,則不用修改了  
                          continue;  
                      str[l]=st;  
                      if(l>=2&&str[l-2]=='w'&&str[l-1]=='b'&&str[l]=='w')  
                      {  
                          if(a[l]==0)//若改之前是不符合要求的串,則更新  
                              update(1, 0,n,l,1);  
                          a[l]=1;  
                      }  
                      else if(l>=2&&a[l]==1)//若改之前是符合要求的串,則更新  
                      {  
                          update(1, 0,n,l,0);  
                          a[l]=0;  
                      }  
                      if(l>=1&&str[l]=='b'&&str[l-1]=='w'&&str[l+1]=='w')  
                      {  
                          if(a[l+1]==0)  
                              update(1, 0,n,l+1,1);  
                          a[l+1]=1;  
                      }  
                      else if(l<n-1&&l>=1&&a[l+1]==1) a[l+1]=0,update(1, 0,n,l+1,0);  
                      if(str[l]=='w'&&str[l+1]=='b'&&str[l+2]=='w')  
                      {  
                          if(a[l+2]==0)  
                              update(1, 0,n,l+2,1); 
                          a[l+2]=1;  
                      }  
                      else if(l<n-2&&a[l+2]==1) a[l+2]=0,update(1, 0,n,l+2,0);   
                  }  
              }  
          }  
          return 0;  
      }

       

       

      posted on 2012-08-21 15:54  More study needed.  閱讀(239)  評論(0)    收藏  舉報

      導航

      書山有徑勤為路>>>>>>>>

      <<<<<<<<學海無涯苦作舟!

      主站蜘蛛池模板: 中文毛片无遮挡高潮免费| 亚洲国产性夜夜综合| 天堂一区人妻无码| 在线看av一区二区三区| 中文区中文字幕免费看| 中文在线天堂中文在线天堂| 精品国偷自产在线视频99| 精品国产成人午夜福利| 不卡一区二区国产精品| 丰满少妇被猛烈进出69影院| 久久香蕉欧美精品| 国产成人综合网在线观看| 日韩精品一区二区亚洲专区| 欧美丰满熟妇xxxx性大屁股| 99热精品久久只有精品| 国产成人a在线观看视频免费| 亚洲一区二区精品动漫| 亚在线观看免费视频入口| 好吊视频在线一区二区三区| av色蜜桃一区二区三区| 欧美高清精品一区二区| 国产精品一二三入口播放| 麻豆一区二区中文字幕| 欧美嫩交一区二区三区| 国产精品一区二区三区性色| yw尤物av无码国产在线观看| 色欧美片视频在线观看| 北流市| 日韩精品亚洲不卡一区二区| 无码日韩av一区二区三区| 国产白嫩护士在线播放| 亚洲夂夂婷婷色拍ww47| 日本一区二区三区四区黄色| 亚洲av与日韩av在线| 人妻蜜臀久久av不卡| 人妻日韩精品中文字幕| 99精品国产一区二区三区| 婷婷丁香五月深爱憿情网| 日本免费人成视频在线观看| 齐齐哈尔市| 国产精品日日摸夜夜添夜夜添无码 |