推荐几个博客: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\n",cnt[i]);
55 }
56 return 0;
57 }
注意两点: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\n",s);
64 }
65 return 0;
66 }
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\n",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 }
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\n",SUM(x1,y1,x2,y2));
57 }
58 }
59 }
60 return 0;
61 }
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\n",SUM(x1,y1,x2,y2));
72 }
73 }
74 }
75 return 0;
76 }
有关二进制在数据结构中的应用: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("\n");
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\n",sum(x,y)%2);
53 }
54 }
55 }
56 return 0;
57 }
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\n",sum(x,y,z)%2);
52 }
53 }
54 }
55 return 0;
56 }
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\n",h,ans);
63 }
64 return 0;
65 }
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\n",ans);
78 }
79 return 0;
80 }
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("\n");
69 }
70 }
71 return 0;
72 }
来源:https://www.cnblogs.com/HDUjackyan/p/8717652.html
