zoukankan      html  css  js  c++  java
  • 专题训练之树状数组

    推荐几个博客:https://blog.csdn.net/int64ago/article/details/7429868搞懂树状数组

    https://blog.csdn.net/z309241990/article/details/9615259区间修改

    https://blog.csdn.net/whereisherofrom/article/details/78922383完整版+题集

    http://www.cnblogs.com/wuyiqi/archive/2011/12/25/2301071.html二进制思想求第k大数

    http://www.cnblogs.com/oa414/archive/2011/07/21/2113234.html二分/二进制思想求第k大数

    一维树状数组模板(区间求和、单点修改)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=1e5+10;
     6 int bit[maxn],n;
     7 
     8 int lowbit(int x)
     9 {
    10     return x&(-x);
    11 }
    12 
    13 void add(int k,int num)
    14 {
    15     while ( k<=n ) {
    16         bit[k]+=num;
    17         k+=lowbit(k);
    18     }
    19 }
    20 
    21 int sum(int k)
    22 {
    23     int s=0;
    24     while ( k ) {
    25         s+=bit[k];
    26         k-=lowbit(k);
    27     }
    28     return s;
    29 }
    树状数组模板(区间求和+单点修改)

    二维树状数组模板(区间求和、单点修改)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=1500;
     6 int bit[maxn][maxn],n;
     7 
     8 int lowbit(int x)
     9 {
    10     return x&(-x);
    11 }
    12 
    13 void add(int x,int y,int num)
    14 {
    15     for ( int i=x;i<=n;i+=lowbit(i) ) {
    16         for ( int j=y;j<=n;j+=lowbit(j) ) {
    17             bit[i][j]+=num;
    18         }
    19     }
    20 }
    21 
    22 int sum(int x,int y)
    23 {
    24     int s=0;
    25     for ( int i=x;i>0;i-=lowbit(i) ) {
    26         for ( int j=y;j>0;j-=lowbit(j) ) {
    27             s+=bit[i][j];
    28         }
    29     }
    30     return s;
    31 }
    32 
    33 int SUM(int x1,int y1,int x2,int y2)
    34 {
    35     return sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1);
    36 }
    二维数组数组模板(区间求和、单点修改)

    1.(HDOJ1541)http://acm.hdu.edu.cn/showproblem.php?pid=1541

    题意:给出N个恒星的坐标(按照y从小到大,若y相同则按照x从小到大输入)。每个恒星的等级于所有在他左下方恒星的数量相等。输出0到n-1等级恒星的数量

    分析:因为题目的顺序是按照y从小到大的顺序输入的。所有可以想象把二维图压缩成一维(或者说是投影到一维平面)。这时候按照读入顺序一步步将横坐标更新进树状数组中,同时对于第i个恒星(xi,yi)的等级为sum(xi),即所有x<=xi数的数量之和。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=1e5+10;
     6 int bit[maxn],n,cnt[maxn];
     7 struct node{
     8     int x;
     9     int y;
    10 }arr[maxn];
    11 
    12 int lowbit(int x)
    13 {
    14     return x&(-x);
    15 }
    16 
    17 void add(int k,int num)
    18 {
    19     while ( k<=n ) {
    20         bit[k]+=num;
    21         k+=lowbit(k);
    22     }
    23 }
    24 
    25 int sum(int k)
    26 {
    27     int s=0;
    28     while ( k ) {
    29         s+=bit[k];
    30         k-=lowbit(k);
    31     }
    32     return s;
    33 }
    34 
    35 int main()
    36 {
    37     int i,j,k,x,y,rk,N;
    38     while ( scanf("%d",&N)!=EOF ) {
    39         memset(cnt,0,sizeof(cnt));
    40         memset(bit,0,sizeof(bit));
    41         n=0;
    42         for ( i=0;i<N;i++ ) {
    43             scanf("%d%d",&arr[i].x,&arr[i].y);
    44             n=max(n,arr[i].x);
    45         }
    46         n++;
    47         for ( i=0;i<N;i++ ) {
    48             x=arr[i].x+1;
    49             y=arr[i].y+1;
    50             rk=sum(x);
    51             cnt[rk]++;
    52             add(x,1);
    53         }
    54         for ( i=0;i<N;i++ ) printf("%d
    ",cnt[i]);
    55     }
    56     return 0;
    57 }
    HDOJ1541

    注意两点:A.树状数组的n(横坐标的最大值)和恒星数量的N不是同一个N 

    B.对于树状数组的题目要特别注意是否会有0这个量。树状数组无法处理0.所有这题将所有横坐标都+1了

    2.(POJ1990)http://poj.org/problem?id=1990

    题意:有N头牛,每头牛都有一个横坐标xi和音量yi。对于任意两头牛它们之间交流需要耗费max(yi,yj)*abs(xi-xj),即音量中大的值乘以它们之间的距离。现在求所有牛相互交谈需要耗费多少。

    分析:因为音量需要取较大的那个,所以我们对音量进行从小到大的排序,这样就可以保证每次计算时都可以选当前那个较大的音量进行计算。而对当前那头牛的距离xi与其他牛距离的关系讨论时,我们则需要分类讨论,分成x<xi和x>xi的进行考虑。我们利用两个树状数组一个存数量(即在距离x那个地方+1表示该位置有一头牛),记作num[];而另一个树状则保存距离(即在x的地方+x),记做bit[]。那么对于第i头牛(均为排序后,以下同)与前面那i-1头牛的消耗为yi*坐标差之和,坐标差之和由两部分组成,x*(小于x坐标的牛的数目)-(小于x坐标的牛的距离之和),另一部分为(大于x坐标的牛的距离之和)-x*(小于x坐标的牛的数量)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const ll maxn=2e4+10;
     7 ll bit[maxn],n,num[maxn];
     8 struct node{
     9     ll x;
    10     ll v;
    11 }arr[maxn];
    12 
    13 bool cmp(node a,node b)
    14 {
    15     return a.v<b.v;
    16 }
    17 
    18 ll lowbit(ll x)
    19 {
    20     return x&(-x);
    21 }
    22 
    23 void add(ll* b,ll k,ll num)
    24 {
    25     while ( k<=n ) {
    26         b[k]+=num;
    27         k+=lowbit(k);
    28     }
    29 }
    30 
    31 ll sum(ll* b,ll k)
    32 {
    33     ll s=0;
    34     while ( k ) {
    35         s+=b[k];
    36         k-=lowbit(k);
    37     }
    38     return s;
    39 }
    40 
    41 int main()
    42 {
    43     ll m,i,j,k,x,y,z,N,s,cnt,u,v;
    44     while ( scanf("%lld",&N)!=EOF ) {
    45         n=0;
    46         s=0;
    47         memset(num,0,sizeof(num));
    48         memset(bit,0,sizeof(bit));
    49         for ( i=1;i<=N;i++ ) {
    50             scanf("%lld%lld",&arr[i].v,&arr[i].x);
    51             n=max(n,arr[i].x);
    52         }
    53         sort(arr+1,arr+N+1,cmp);
    54         for ( i=1;i<=N;i++ ) {
    55             x=sum(bit,arr[i].x); //坐标在它前面的所有坐标和 
    56             y=sum(bit,n)-x;
    57             v=sum(num,arr[i].x);
    58             u=sum(num,n)-v;
    59             s+=(arr[i].x*(v-u)-x+y)*arr[i].v;
    60             add(bit,arr[i].x,arr[i].x);
    61             add(num,arr[i].x,1);
    62         }
    63         printf("%lld
    ",s);
    64     }
    65     return 0;
    66 }
    POJ1990

    3.(POJ3321)http://poj.org/problem?id=3321

    题意:有一颗苹果树,苹果树上有分叉,刚开始苹果树上每个节点都有一个苹果。现有两个操作:C X,如果X点有苹果,则拿掉,如果没有,则新长出一个;Q X,查询X点与它的所有后代分支一共有几个苹果。

    分析:DFS序+树状数组(/线段树)。首先利用DFS序求出每个节点对应的区间范围。同时设置一个bool型的vis数组判断该位置上是否有苹果的存在。对于操作C来说,如果vis[x]为true,则利用树状数组在x位置上+1,否则-1.而对于操作Q,利用树状数组查询[in[x],out[x]]这个区间的苹果树总和。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 using namespace std;
     6 const int maxn=1e5+10;
     7 int bit[maxn],n,cnt,in[maxn],out[maxn];
     8 vector<vector<int> >G(maxn);
     9 bool vis[maxn];
    10 
    11 int lowbit(int x)
    12 {
    13     return x&(-x);
    14 }
    15 
    16 void add(int k,int num)
    17 {
    18     while ( k<=cnt ) {
    19         bit[k]+=num;
    20         k+=lowbit(k);
    21     }
    22 }
    23 
    24 int sum(int k)
    25 {
    26     int s=0;
    27     while ( k ) {
    28         s+=bit[k];
    29         k-=lowbit(k);
    30     }
    31     return s;
    32 }
    33 
    34 void dfs(int u)
    35 {
    36     in[u]=++cnt;
    37     for ( int i=0;i<G[u].size();i++ ) {
    38         int v=G[u][i];
    39         dfs(v);
    40     }
    41     out[u]=cnt;
    42 }
    43 
    44 int main()
    45 {
    46     int n,m,i,j,k,x,y,z,u,v;
    47     char s[10];
    48     while ( scanf("%d",&n)!=EOF ) {
    49         memset(bit,0,sizeof(bit));
    50         for ( i=1;i<=n;i++ ) {
    51             G[i].clear();
    52             vis[i]=true;
    53         }
    54         for ( i=1;i<n;i++ ) {
    55             scanf("%d%d",&x,&y);
    56             G[x].push_back(y);
    57         }
    58         cnt=0;
    59         dfs(1);
    60         for ( i=1;i<=n;i++ ) add(in[i],1);
    61         scanf("%d",&m);
    62         while ( m-- ) {
    63             scanf("%s%d",s,&x);
    64             if ( s[0]=='Q' ) {
    65                 u=sum(out[x]);
    66                 if ( in[x]!=1 ) u-=sum(in[x]-1);
    67                 printf("%d
    ",u);
    68             }
    69             else {
    70                 if ( vis[x] ) {
    71                     add(in[x],-1);
    72                     vis[x]=false;
    73                 }
    74                 else {
    75                     add(in[x],1);
    76                     vis[x]=true;
    77                 }
    78             }
    79         }
    80     }
    81     return 0;
    82 }
    POJ3321

    4.(POJ1195)http://poj.org/problem?id=1195

    题意:初始时给定一个大小为n*n的区域,现有4种操作。0为初始化该区域,该操作只会出现一次且在最初出现。1 x,y,z为在(x,y)上+z。 2 x1,y1,x2,y2为查询该区域内的数量。 3 为退出查询

    分析:裸的二维树状数组,注意点同下一题

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 using namespace std;
     6 typedef long long ll;
     7 const int maxn=1500;
     8 ll bit[maxn][maxn],n;
     9 
    10 ll lowbit(ll x)
    11 {
    12     return x&(-x);
    13 }
    14 
    15 void add(ll x,ll y,ll num)
    16 {
    17     for ( ll i=x;i<=n;i+=lowbit(i) ) {
    18         for ( ll j=y;j<=n;j+=lowbit(j) ) {
    19             bit[i][j]+=num;
    20         }
    21     }
    22 }
    23 
    24 ll sum(ll x,ll y)
    25 {
    26     ll s=0;
    27     for ( ll i=x;i>0;i-=lowbit(i) ) {
    28         for ( ll j=y;j>0;j-=lowbit(j) ) {
    29             s+=bit[i][j];
    30         }
    31     }
    32     return s;
    33 }
    34 
    35 ll SUM(ll x1,ll y1,ll x2,ll y2)
    36 {
    37     return sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1);
    38 }
    39 
    40 int main()
    41 {
    42     ll m,i,j,k,x,y,z,x1,y1,x2,y2;
    43     while ( scanf("%lld%lld",&m,&n)!=EOF ) {
    44         memset(bit,0,sizeof(bit));
    45         while ( scanf("%lld",&m) && m!=3 ) {
    46             if ( m==1 ) {
    47                 scanf("%lld%lld%lld",&x,&y,&z);
    48                 x++;y++;
    49                 add(x,y,z);
    50             }
    51             else if ( m==2 ) {
    52                 scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
    53                 x1++;x2++;y1++;y2++;
    54                 if ( x1>x2 ) swap(x1,x2);
    55                 if ( y1>y2 ) swap(y1,y2);
    56                 printf("%lld
    ",SUM(x1,y1,x2,y2));
    57             }
    58         }
    59     }
    60     return 0;
    61 }
    POJ1195

    5.(HDOJ2642)http://acm.hdu.edu.cn/showproblem.php?pid=2642

    题意:有一个最大不超过1000*1000的二维平面,每个点有一颗星星,初始时都是暗的。现在有3种操作。D x y使(x,y)这个点上的星星暗掉。B(x,y)使(x,y)这个点上的星星亮起来。Q x1,x2,y1,y2。查询在这个区域内亮着的点的个数

    分析:裸的二维树状数组。但是要注意两点,下标必须从1开始,而不是0(对所有输入的x和y采用+1的方式处理)。在查询时需要保证x1<=x2&&y1<=y2

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 using namespace std;
     6 const int maxn=1005;
     7 int bit[maxn][maxn],n;
     8 bool vis[maxn][maxn];
     9 
    10 int lowbit(int x)
    11 {
    12     return x&(-x);
    13 }
    14 
    15 void add(int x,int y,int num)
    16 {
    17     for ( int i=x;i<=n;i+=lowbit(i) ) {
    18         for ( int j=y;j<=n;j+=lowbit(j) ) {
    19             bit[i][j]+=num;
    20         }
    21     }
    22 }
    23 
    24 int sum(int x,int y)
    25 {
    26     int s=0;
    27     for ( int i=x;i>0;i-=lowbit(i) ) {
    28         for ( int j=y;j>0;j-=lowbit(j) ) {
    29             s+=bit[i][j];
    30         }
    31     }
    32     return s;
    33 }
    34 
    35 int SUM(int x1,int y1,int x2,int y2)
    36 {
    37     return sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1);
    38 }
    39 
    40 int main()
    41 {
    42     int m,i,j,k,x,y,z,x1,y1,x2,y2;
    43     char s[10];
    44     while ( scanf("%d",&m)!=EOF ) {
    45         n=1000;
    46         memset(bit,0,sizeof(bit));
    47         memset(vis,false,sizeof(vis));
    48         while ( m-- ) {
    49             scanf("%s",s);
    50             if ( s[0]=='B') {
    51                 scanf("%d%d",&x,&y);
    52                 x++;y++;
    53                 if ( !vis[x][y] ) {
    54                     add(x,y,1);
    55                     vis[x][y]=true;
    56                 }
    57             }
    58             else if ( s[0]=='D' ) {
    59                 scanf("%d%d",&x,&y);
    60                 x++;y++;
    61                 if ( vis[x][y] )  {
    62                     add(x,y,-1);
    63                     vis[x][y]=false;
    64                 }
    65             }
    66             else {
    67                 scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
    68                 x1++;x2++;y1++;y2++;
    69                 if ( x1>x2 ) swap(x1,x2);
    70                 if ( y1>y2 ) swap(y1,y2);
    71                 printf("%d
    ",SUM(x1,y1,x2,y2));
    72             }
    73         }
    74     }
    75     return 0;
    76 }
    HDOJ2642

    有关二进制在数据结构中的应用:https://wenku.baidu.com/view/1e51750abb68a98271fefaa8

    6.(POJ2155)http://poj.org/problem?id=2155

    题意:裸二维树状数组

    分析:见以上那篇论文。采用二维树状数组进行保存,每次区间更新转化成点更新,每次更新都++,最后对2取模即可得到0/1。注意二维更新的点数是2^2个。n维更新的点数是2^n个。同时需要注意输出格式。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=1005;
     6 int bit[maxn][maxn],n;
     7 
     8 int lowbit(int x)
     9 {
    10     return x&(-x);
    11 }
    12 
    13 void add(int x,int y)
    14 {
    15     for ( int i=x;i<=n;i+=lowbit(i) ) {
    16         for ( int j=y;j<=n;j+=lowbit(j) ) bit[i][j]++;
    17     }
    18 }
    19 
    20 int sum(int x,int y)
    21 {
    22     int s=0;
    23     for ( int i=x;i>0;i-=lowbit(i) ) {
    24         for ( int j=y;j>0;j-=lowbit(j) ) s+=bit[i][j];
    25     }
    26     return s;
    27 }
    28 
    29 int main()
    30 {
    31     int T,m,i,j,k,x,y,z,x1,x2,y1,y2,q;
    32     bool flag;
    33     char s[10];
    34     scanf("%d",&T);
    35     flag=true;
    36     while ( T-- ) {
    37         scanf("%d%d",&n,&q);
    38         memset(bit,0,sizeof(bit));
    39         if ( flag ) flag=false;
    40         else printf("
    ");
    41         while ( q-- ) {
    42             scanf("%s",s);
    43             if ( s[0]=='C' ) {
    44                 scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    45                 add(x1,y1);
    46                 add(x1,y2+1);
    47                 add(x2+1,y1);
    48                 add(x2+1,y2+1);
    49             }
    50             else {
    51                 scanf("%d%d",&x,&y);
    52                 printf("%d
    ",sum(x,y)%2);
    53             }
    54         }
    55     }
    56     return 0;
    57 }
    POJ2155

    7.(HDOJ3584)http://acm.hdu.edu.cn/showproblem.php?pid=3584

    题意:裸三维树状数组

    分析:见以上那篇论文。更新8个点即可。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=105;
     6 int bit[maxn][maxn][maxn],n;
     7 
     8 int lowbit(int x)
     9 {
    10     return x&(-x);
    11 }
    12 
    13 void add(int x,int y,int z)
    14 {
    15     for ( int i=x;i<=n;i+=lowbit(i) ) {
    16         for ( int j=y;j<=n;j+=lowbit(j) ) 
    17             for ( int k=z;k<=n;k+=lowbit(k) ) bit[i][j][k]++;
    18     }
    19 }
    20 
    21 int sum(int x,int y,int z)
    22 {
    23     int s=0;
    24     for ( int i=x;i>0;i-=lowbit(i) ) {
    25         for ( int j=y;j>0;j-=lowbit(j) ) 
    26             for ( int k=z;k>0;k-=lowbit(k) ) s+=bit[i][j][k];
    27     }
    28     return s;
    29 }
    30 
    31 int main()
    32 {
    33     int T,m,i,j,k,x,y,z,x1,x2,y1,y2,z1,z2,s,q;
    34     while ( scanf("%d%d",&n,&q)!=EOF ) {
    35         memset(bit,0,sizeof(bit));
    36         while ( q-- ) {
    37             scanf("%d",&s);
    38             if ( s==1 ) {
    39                 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
    40                 add(x1,y1,z1);
    41                 add(x2+1,y1,z1);
    42                 add(x1,y2+1,z1);
    43                 add(x1,y1,z2+1);
    44                 add(x1,y2+1,z2+1);
    45                 add(x2+1,y1,z2+1);
    46                 add(x2+1,y2+1,z1);
    47                 add(x2+1,y2+1,z2+1);
    48             }
    49             else {
    50                 scanf("%d%d%d",&x,&y,&z);
    51                 printf("%d
    ",sum(x,y,z)%2);
    52             }
    53         }
    54     }
    55     return 0;
    56 }
    HDOJ3584

    8.(POJ3067)http://poj.org/problem?id=3067

    题意:日本有东海岸和西海岸,西海岸有n座城市,东海岸有m座城市,有q条高铁连接东西海岸,先求高铁之间的交点有多少

    分析:先来看看什么时候会有交点,对于高铁路线1(x1,y1)(表示东海岸的x1与西海岸的y1相连,下同)和高铁路线2(x2,y2)当x1<x2&&y1>y2时有交点。那么我们可以考虑根据x对高铁路线进行从小到大的排序,当x相同时y考虑从小到大进行排序(因为x相同时不会有交点,所以只有y从小到大进行排序后才对结果不会产生影响)。采用逐一更新的方式,每次输入一条高铁线路时,利用树状数组求出有多少条线路的y是大于该线路的y,然后再更新该线路的y。

    注意:高铁线路的范围比较大;最后的答案要用long long储存

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn=1005;
     7 const int maxm=1e6+10;
     8 int bit[maxn],n,m;
     9 struct node{
    10     int x;
    11     int y;
    12 }arr[maxm];
    13 
    14 int lowbit(int x)
    15 {
    16     return x&(-x);
    17 }
    18 
    19 void add(int k,int num)
    20 {
    21     while ( k<=m ) {
    22         bit[k]+=num;
    23         k+=lowbit(k);
    24     }
    25 }
    26 
    27 int sum(int k)
    28 {
    29     int s=0;
    30     while ( k ) {
    31         s+=bit[k];
    32         k-=lowbit(k);
    33     }
    34     return s;
    35 }
    36 
    37 bool cmp(node a,node b)
    38 {
    39     if ( a.x==b.x ) return a.y<b.y;
    40     return a.x<b.x;
    41 }
    42 
    43 int main()
    44 {
    45     int T,h,i,j,k,x,y,z,q;
    46     ll ans;
    47     scanf("%d",&T);
    48     for ( h=1;h<=T;h++ ) {
    49         scanf("%d%d%d",&n,&m,&q);
    50         memset(bit,0,sizeof(bit));
    51         for ( i=0;i<q;i++ ) {
    52             scanf("%d%d",&arr[i].x,&arr[i].y);
    53         }
    54         sort(arr,arr+q,cmp);
    55         ans=0;
    56         for ( i=0;i<q;i++ ) {
    57             x=arr[i].x;
    58             y=arr[i].y;
    59             ans+=(i-sum(y));
    60             add(y,1);
    61         }
    62         printf("Test case %d: %I64d
    ",h,ans);
    63     }
    64     return 0;
    65 }
    POJ3067

    9.(HDOJ3465)http://acm.hdu.edu.cn/showproblem.php?pid=3465

    题意:有N条直线,先给定一个范围(L,R),每条直线给出两点坐标(x1,y1),(x2,y2),先求所有直线在开区间(L,R)中的交点有多少个

    分析:求出每条直线与L和R的交点后通过离散化就可以转化为上面那题的形式了。此题有几个点需要注意,可能存在垂直于x轴的直线(即斜率k不存在)需要特别考虑。另外离散化的方法是先按ry从小到大排序然后按顺序给id(此处的id类似于上一题的y)赋值。离散化后的思路大致用上一题

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=5e4+10;
     6 struct node{
     7     double ly,ry;
     8     int id;
     9 }arr[maxn];
    10 int n,bit[maxn];
    11 
    12 int lowbit(int x)
    13 {
    14     return x&(-x);
    15 }
    16 
    17 void add(int k)
    18 {
    19     while ( k<=n ) {
    20         bit[k]++;
    21         k+=lowbit(k);
    22     }
    23 }
    24 
    25 int sum(int k)
    26 {
    27     int s=0;
    28     while ( k ) {
    29         s+=bit[k];
    30         k-=lowbit(k);
    31     }
    32     return s;
    33 }
    34 
    35 bool cmp1(node a,node b)
    36 {
    37     if ( a.ly==b.ly ) return b.ly<a.ly;
    38     return a.ly<b.ly;
    39 }
    40 
    41 bool cmp2(node a,node b)
    42 {
    43     if ( a.ry==b.ry ) return a.ly<b.ly;
    44     return a.ry<b.ry;
    45 }
    46 
    47 int main()
    48 {
    49     int N,i,j,now;
    50     long long ans;
    51     double L,R,x1,y1,x2,y2,k,b;
    52     while ( scanf("%d",&N)!=EOF ) {
    53         memset(bit,0,sizeof(bit));
    54         scanf("%lf%lf",&L,&R);
    55         n=0;
    56         now=0;
    57         for ( i=0;i<N;i++ ) {
    58             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    59             if ( x1==x2 ) {
    60                 if ( L<x1 && x1<R ) now++;
    61             }
    62             else {
    63                 k=(y2-y1)/(x2-x1);
    64                 b=y1-x1*k;
    65                 arr[n].ly=L*k+b;
    66                 arr[n++].ry=R*k+b;
    67             }
    68         }
    69         sort(arr,arr+n,cmp2);
    70         for ( i=0;i<n;i++ ) arr[i].id=i+1;
    71         ans=n*now;
    72         sort(arr,arr+n,cmp1);
    73         for ( i=0;i<n;i++ ) {
    74             ans+=(i-sum(arr[i].id));
    75             add(arr[i].id);
    76         }
    77         printf("%lld
    ",ans);
    78     }
    79     return 0;
    80 }
    HDOJ3465

    10.(POJ2481)http://poj.org/problem?id=2481

    题意:有m头牛,每头牛都有一个吃草的区间[s,e],对于牛i和牛j,当牛j吃草区间是牛i的真子集时我们就说牛j比牛i强壮,先求对于每头牛有多少牛比它们强壮

    分析:对牛按E从大到小,S从小到大进行排序进行离线操作。每次求sum(s[i]),所得的数量一定是比当前这头牛强壮的牛的数量。注意特判,当两头牛吃草的区间是一样时则不计算入内。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=1e5+10;
     6 int n,bit[maxn],num[maxn];
     7 struct node{
     8     int s;
     9     int e;
    10     int index;
    11 }arr[maxn];
    12 
    13 int lowbit(int x)
    14 {
    15     return x&(-x);
    16 }
    17 
    18 void add(int k)
    19 {
    20     while ( k<=n ) {
    21         bit[k]++;
    22         k+=lowbit(k);
    23     }
    24 }
    25 
    26 int sum(int k)
    27 {
    28     int s=0;
    29     while ( k ) {
    30         s+=bit[k];
    31         k-=lowbit(k);
    32     }
    33     return s;
    34 }
    35 
    36 bool cmp(node a,node b)
    37 {
    38     if ( a.e==b.e ) return a.s<b.s;
    39     return a.e>b.e;
    40 }
    41 
    42 int main()
    43 {
    44     int m,i,j,k,x,y,z,cnt;
    45     while ( scanf("%d",&m)!=EOF && m ) {
    46         memset(bit,0,sizeof(bit));
    47         memset(num,0,sizeof(num));
    48         n=0;
    49         for ( i=0;i<m;i++ ) {
    50             scanf("%d%d",&arr[i].s,&arr[i].e);
    51             arr[i].s++;arr[i].e++;
    52             n=max(n,arr[i].e);
    53             arr[i].index=i;
    54         }
    55         sort(arr,arr+m,cmp);
    56         cnt=0;
    57         for ( i=0;i<m;i++ ) {
    58             if ( i!=0 ){
    59                 if ( arr[i].s==arr[i-1].s && arr[i].e==arr[i-1].e ) cnt++;
    60                 else cnt=0;
    61             } 
    62             num[arr[i].index]+=(sum(arr[i].s)-cnt);
    63             add(arr[i].s);
    64         }
    65         for ( i=0;i<m;i++ ) {
    66             printf("%d",num[i]);
    67             if ( i!=m-1 ) printf(" ");
    68             else printf("
    ");
    69         }
    70     }
    71     return 0;
    72 }
    POJ2481
  • 相关阅读:
    切换到真正的最高权限 SYSTEM 账户界面
    javascript中replace的正则表达式语法
    微软系统漏洞_超长文件路径打造私人地盘
    JAVA控制台
    PowerPoint绘图笔不能用
    《JavaScript核心技术》
    Catch(...) C++中三个点
    XMLHttp连续调用SEND需要注意的问题
    Wscript中的事件机制
    JavaScript(JS)常用的正则表达式
  • 原文地址:https://www.cnblogs.com/HDUjackyan/p/8717652.html
Copyright © 2011-2022 走看看