Fenwick

hdu1394 这题说的是给了一个序列计算这个序列的逆序对总共要进行n次 每次都将目前的第一个放到序列的最后一个位置然后 计算一次逆序对 这样我们只需要先求一次逆序对 然后接着每次都用F=F+(n-T[i]-1)+T[i]  求得下一个 就不需要每次都去算逆序对

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 5005;
int C[5005];
int T[5005];
int n;
int lowbit(int x){
    return x&(-x);
}
int sum(int x){
    int ret = 0;
    while(x>0){
         ret+=C[x]; x-=lowbit(x);
    }
    return ret;
}
void add(int x,int d){
    while(x<=n){
        C[x]+=d; x+=lowbit(x);
    }
}
int Fenwick(int st){
       int ans =0;
       for(int i = 0;i<n ;++ i){
            add(T[(st+i)%n],1);
            int S1=sum(n);
            int S2 =sum(T[(st+i)%n]);
            ans+=S1-S2;
       }
       return ans;
}
int main()
{
      while(scanf("%d",&n) == 1){
          int ans =0x7fffffff;
          for(int i = 0 ; i< n ;++ i){
                scanf("%d",&T[i]);
                ++T[i];
            }
            memset(C,0,sizeof(C));
            int f=Fenwick(0);
            for(int i=0 ; i<n ;++i){

                f=f+n-T[i]-(T[i]-1);
                ans =min(ans,f);
            }
          printf("%d\n",ans);
      }
      return 0;
}

acdream1127 这题说的是给了两个 大站点  在大站点的他们附近有许多的小站点 小站点只能通过大站点与外界通信 大站点有一个圆形的作用范围 这个范围内的点可以接受信息 范围外的不能好了就这样,这样他给了很多个不同的半径 计算在每个半径不同的情况下又多少个点不在范围内  因为有两个点所以 每个点就形成了与他们距离 的一个二维的相对坐标,当他不在第一个点的坐标内的时候我们可以将他 放进 第二维的树状数组中 通过求和判断是否在第二维的相应的坐标里这样我们 用 第二点的半径所在的位置去进行一次求和 和 总数n   sum(n)得到的是 目前不在 第一个范围内的点的个数sum(第二个半径的位置) 得到的是在第二个范围内点的个数 然后相减一下就得到了

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=100005;
int C[maxn],N;
struct node{
   long long x,y;
   int num;
   bool operator <(const node &A)const {
      return x>=A.x;
   }
}P[maxn],Query[maxn];
long long dist[maxn];
bool cmp1(node A,node B){
   return A.x >= B.x ;
}
int lowbit(int x){
   return x&(-x);
}
void add(int x,int d){
      while(x<=N){
         C[x]+=d; x+=lowbit(x);
      }
}
int sum(int x){
      int ans =0;
      while(x>0){
          ans+=C[x];
          x-=lowbit(x);
      }
      return ans;
}
int ans[maxn];
int main()
{
      long long x1,y1,x2,y2;
      while(scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2)==4){
           scanf("%d",&N);
           for(int i = 0; i<N; ++ i){
                long long x,y;
                scanf("%I64d%I64d",&x,&y);
                P[i].x=(x-x1)*(x-x1)+(y-y1)*(y-y1);
                P[i].y=(x-x2)*(x-x2)+(y-y2)*(y-y2);
                dist[i+1]=P[i].y;
           }
           int M;
           scanf("%d",&M);
           for(int i = 0; i<M; ++i){
                long long r1,r2;
                scanf("%I64d%I64d",&r1,&r2);
                Query[i].x=r1*r1;
                Query[i].y=r2*r2;
                Query[i].num=i;
           }
           sort(P,P+N,cmp1);
           sort(dist+1,dist+1+N);
           int num=unique(dist+1,dist+1+N)-1-dist;
           sort(Query,Query+N,cmp1);
           int id=0;
           memset(C,0,sizeof(C));
           for(int i =0; i<M; ++ i) {
                 while( id<N && P[id].x >= Query[i].x ) {
                      int loc = lower_bound( dist + 1, dist+1+num, P[id].y )-dist;
                      add(loc,1);
                      ++id;
                 }
                int lox = lower_bound(dist + 1, dist+1+num, Query[i].y)-dist-1;
                int SN =sum(N);
                int SLOX =sum(lox);
                ans[Query[i].num] = SN -SLOX;
           }
           for(int i =0; i<M; ++i)
            printf("%d\n",ans[i]);
      }
      return 0;
}

#247div2 E 题 这题说的是 有n个试管每个试管中有一些汞 然后又两种操作 第一种是将某个试管中的汞的体积变成 xi 然后将第二种操作是将 Vi 升的水倒入 这n个试管中求 有装水的试管中水的体积最大的 体积最小, 这样我们可以去二分找这个可能的高度 ,将所有可能的高度进行一次离散化,然后不断的用树状数组去修改和查询,然后得到了正解

#include <iostream>
#include <cstdio>
#include <string.h>
#include <set>
#include <map>
using namespace std;
const int maxn=200005;
int h[maxn],T[100005],n,q,max_h=0;
int p[100005],x[100005],cap[maxn];
__int64 V[100005];
__int64 A[maxn],B[maxn];
int lowbit(int x){
  return x&(-x);
}
void add(__int64 *C, int x,__int64 d){
      while(x<=max_h){
         C[x]+=d; x+=lowbit(x);
      }
}
__int64 sum(__int64 *C,int x){
     __int64 ans=0;
     while(x>0){
         ans+=C[x]; x-=lowbit(x);
     }
     return ans;
}
__int64 solve(int H){
    __int64 num=sum(A,H);
    __int64 remain = sum(B,H);
    __int64 line=cap[H];
    __int64 ans = num * line - remain;
    return ans;
}
int main()
{
       set<int>Live;
       scanf("%d%d",&n,&q);
       for(int i =1; i<=n; ++i){
          scanf("%d",&h[i]);
          Live.insert(h[i]);
       }

       for( int i =0; i<q; ++i){
          scanf("%d",&T[i]);
          if(T[i] == 1){
             scanf("%d%d",&p[i],&x[i]);
             Live.insert(x[i]);
          }else scanf("%I64d",&V[i]);
       }
       map<int,int>MP;
       for(set<int>::iterator it=Live.begin(); it!=Live.end(); ++it){
           int E = *it;
           MP.insert(make_pair(E,max_h+1));
           ++max_h;
           cap[max_h] = E;
       }
       for(int i =1; i<=n; ++i){
          int loc = MP[h[i]];
          add(A,loc,1);
          add(B,loc,h[i]);
       }
       for(int e=0; e<q; ++e){
           if(T[e]==1){
                int t = p[e];
                int loc = MP[h[t]];
                add(A, loc, -1);
                add(B, loc, -h[t]);
                h[t] = x[e];
                loc  = MP[h[t]];
                add(A, loc, 1);
                add(B, loc, h[t]);
           }else{
                int H=0;
                for(int i =20 ; i>=0; -- i){
                    if((H+(1<<i))>max_h) continue;
                    if(solve((H+(1<<i)))<=V[e])
                        H=H+(1<<i);
                }
                double remain=solve(H);
                double num=sum(A,H);
                double ans = cap[H];
                ans =ans + (double(V[e]) - remain)/num;
                printf("%.5lf\n",ans);
           }

       }
       return 0;
}

uva1513 这 题 说 的 是 给 了 一 个 堆(从1...到n) 然 后 从 堆 中 的 某 个 位 置 取 一 个 点 出 来 放在最顶端 每次 操作时输出在该点的上方有多少个点用树状数组去查询 自然前面预留m个位置 可 以 放 后 面 堆 叠 的 在 前 面 的 然后每次操作记录一下该点所在的位置

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn=100005;
int n,m,local[maxn];
int C[maxn*2],ans[maxn];
int lowbit(int x){
  return x&(-x);
}
void add(int x,int d){
     while(x<=n+m){
        C[x]+=d;
        x+=lowbit(x);
     }
}
int sum(int x){
    int ans=0;
    while(x>0){
        ans+=C[x];
        x-=lowbit(x);
    }
    return ans;
}
int main()
{
    int cas;
    scanf("%d",&cas);
    while( cas -- ){
         scanf("%d%d",&n,&m);
       for(int i=0;i<=n+m; ++i)C[i]=0;
       for(int i=1; i<=n; ++i){
            local[i]=i+m;
            add(m+i,1);
       }
       int len=0;
       for( int i=m; i>0 ; --i){
            int a;
            scanf("%d",&a);
            ans[len++]=sum(local[a]-1);
            add(local[a],-1);
            local[a]=i;
            add(local[a],1);
        }
        for(int i=0;i<len-1; ++i)
            printf("%d ",ans[i]);
        printf("%d\n",ans[len-1]);
    }
    return 0;
}

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

#include <iostream>
#include<cstdio>
#include <string.h>
using namespace std;
const int maxn = 50005;
int n,K,S[maxn],ans[maxn],C[maxn];
int lowbit(int x){
   return x&(-x);
}
void add(int x,int d){
    while(x<=K){
         C[x] += d; x+=lowbit(x);
    }
}
int sum(int x){
   int ans=0;
   while(x>0){
      ans+=C[x]; x-=lowbit(x);
   }
   return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(C,0,sizeof(C));
        scanf("%d",&K);
        for( int i=0; i<K; ++i )
            scanf("%d",&S[i]);
        for(int i=1; i<=K ; ++i)
            add(i,1);
        for(int i=0; i<K; ++i){
            int L=1,R=K;
            while(L<R){
                int mid=L+((R-L)>>1);
                int num=sum(mid);
                if(num>=(S[i]+1))
                    R=mid;
                else L=mid+1;
            }
            add(L,-1);
            ans[i]=L;
        }
        for(int i=0;i<K-1; ++i)
            printf("%d ",ans[i]);
        printf("%d\n",ans[K-1]);
    }
    return 0;
}

hdu4863 这题说的是给了 一个公司有 M 个任务 但是有N 台机器每台机器 只能完成一项任务,每个任务只允许一台机器完成,每个任务有一个完成时间和等级 , 每台机器有等级和所能承受的最大时间,然后我们先将按照时间排序 时间形同的任务 ,等级大的放前面,然后每次将时间大于等于当前任务的机器的等级放入树状数组中每次去修改树状数组

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
struct point{
   int timef,rankf;
   bool operator < (const point A) const{
      return timef>A.timef||(timef==A.timef&&rankf>=A.rankf);
   }
}Task[200005],machine[200005];
__int64 X[2446],Y[205];
int lowbit(int x){
  return x&(-x);
}
void add(__int64 *C, int x, int d,int N){
    while(x<=N){
        C[x]+=d; x+=lowbit(x);
    }
}
__int64 sum(__int64 *C, int x){
    __int64 ans=0;
    while(x>0){
        ans+=C[x]; x-=lowbit(x);
    }
    return ans;
}
bool bit_time(int D)
{
   __int64 zong = sum(X,1440);
   __int64 di=sum(X,D-1);
   if(zong-di<=0)return false;
  // add(X,D,-1,1440);
   return  true;
}
bool bit_rank(int D)
{
   __int64 zong = sum(Y,101);
   __int64 di = sum(Y,D-1);
   __int64 er = zong-di;
   if(er<=0)return false;
   int L = D , R =101;
   while(L<R){
      int mid=(R+L)/2;
      __int64 W =sum(Y,mid)-di;
      if(W==0)L=mid+1;
      else R=mid;
   }
   add(Y,L,-1,101);
   return true;
}
void solve(int N,int M)
{
      __int64 ans=0;
      int s=0,num=0;
      for(int i=0; i<N; ++i)
        {
             add(X,machine[i].timef,1,1440);
        }

      for(int i=0; i<M; ++i){
           while(s<N&&machine[s].timef>=Task[i].timef){
                add(Y,machine[s].rankf,1,101);
                s++;
           }
           if(bit_time(Task[i].timef)){
              if(bit_rank(Task[i].rankf)){
                    add(X,Task[i].timef,-1,1440);
                 ans+= 500*Task[i].timef+2*(Task[i].rankf-1);
                 num++;
              }
           }
      }
      printf("%d %I64d\n",num,ans);
}
int main()
{
     int N,M;
     while(scanf("%d%d",&N,&M)==2)
        {
            memset(X,0,sizeof(X));
            memset(Y,0,sizeof(Y));
              for(int i =0 ; i<N; ++i){
                scanf("%d%d",&machine[i].timef,&machine[i].rankf);
                machine[i].rankf++;
              }
              for(int i=0; i<M; ++i){
                    scanf("%d%d",&Task[i].timef,&Task[i].rankf);
                    Task[i].rankf++;
              }
              sort(machine,machine+N);
              sort(Task,Task+M);
              solve(N,M);
        }
    return 0;
}
/*
3 4
100 3
101 2
99 2
99 3
100 3
100 2
99 2

*/

cf459D 题说的是 计算 [1,i] 中 值等于ai 的个数 x1, 求出[j,n]中 aj的 个数 x2 其中i小于 j 然后求出,使得x1小于x2的ij的对数,首先对数组进行离散然后,从后往前每个位子都将从该位置的aj以及该位置以后aj的个数,插入树状数组中去,然后 枚举每一个i并将相应的aj个数从 树状数组中删去然后 对于每一个ai个数 在数组中找出小于该个数长度的数有多少个,每次加起来就可以了

Fenwick

时间: 2024-10-13 05:20:14

Fenwick的相关文章

POJ 3321 Apple Tree DFS序+fenwick

题目大意:有一颗长满苹果的苹果树,有两个操作. 1.询问以一个点为根的子树中有多少个苹果. 2.看看一个点有没有苹果,假设没有苹果.那么那里就立即长出一个苹果(= =!):否则就把那个苹果摘下来. 思路:进行一次深搜,将每一个节点最開始出现的时间和最后出现的时间记在一个数组里,那么这两点之间的点就是它以及它的子树的二倍,然后就用树状数组来维护区间和即可了. CODE: #include <cstdio> #include <cstring> #include <iostrea

BZOJ 3744 Gty的妹子序列 分块+fenwick

题目大意:强制在线区间无修改逆序对. 思路:看到数据范围发现分块是很显然的.预处理了很多东西,比如说每个块里面的逆序对个数,还有f[i][j]表示从第i块到第j块的逆序对个数.如果仅仅处理到这里的话,后面是不太好处理的.我们还需要一个东西,是每个点对每个块的逆序对个数,并取前缀合优化.否则的话就得用主席树来乱搞,那常数 反正总时间复杂度大概是O(n*sqrt(n)*logn)  强行不到O(n^2) 剩下就是小事了, 比如离散话啥的.. CODE: #include <cmath> #incl

BZOJ 2780 SPOJ 8093 Sevenk Love Oimaster 后缀自动机+fenwick

题目大意:给出一些字符串,给出一些询问,每次问当前串在源串中的几个中出现过. 思路:将所有源串建立广义后缀自动机.每次新的一个串的时候,把last清成root,往里面加的时候,如果last指针往下走的时候已经有节点了,就需要拓展一个新的节点出来,否则就不满足广义后缀自动机的性质.此外,每一个节点代表的不一定是一个串,可能代表的是多个串的子串,所以要在每个点后面挂链,来表示这个节点是属于哪几个串中的子串.后面的事情就比较简单了,把后缀树建立出来,弄出DFS序,离线处所有询问,变成在一段序列中出现过

Binary Indexed Tree (Fenwick Tree)

Binary Indexed Tree 空间复杂度O(N),查询时间复杂度O(lgN). 其中每个元素,存储的是数组中一段(注意起始元素看作1而非0)的和: 假设这个元素下标为i,找到i的最低位1,从最低位1开始的低部表示的是长度,去除最低位1剩下的部分加上1表示的是起始位置,例如: 8二进制表示为100 最低位1也是最高位,从1开始的低部也即100本身,因此长度为8. 去除1以后,剩下为0,加上1以后为1.所以sum[8]表示的是从第1个元素开始的8个元素的和. 又比如11的二进制表示为101

树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)

刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; //一维树状数组基础模板 int lowbit(int x) { return x&(-x); } int c[1001]; int sum(int x) //计算从1到x的数组元素的和 { int

深入理解树状数组

树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值:经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询). 百度上给出了令人难以理解的概念,其实这个东西我也是琢磨了一天,参考了大量博客的笔记才搞清楚了大致思路和原理,说说心得吧! 假设数组a[1..n],那么

Codeforces 628E Zbazi in Zeydabad 树状数组

题意:一个n*m的矩阵,要么是 . 要么是 z ,问可以形成几个大z 分析:(直接奉上官方题解,我感觉说的实在是太好了) Let's precalculate the values zlij, zrij, zldij — the maximal number of letters 'z' to the left, to the right and to the left-down from the position (i, j). It's easy to do in O(nm) time. L

Count of Smaller Numbers After Self

题目: You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i]. Example: Given nums = [5, 2, 6, 1] To the right of 5 there

HDU1166 敌兵布阵(树状数组)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 60510    Accepted Submission(s): 25649 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务