LA - 4329 - Ping pong(树状数组/线段树)
2013-01-05 16:51
232 查看
题意:一条街从西到东住着N(3 <= N <= 20000)位乒乓球选手,每位选手有一个属于自己的等级,3个人,2人比赛,1人当裁判,裁判要住在这2个人之间,且裁判的等级也要在这2人之间,问共能举行几场比赛?
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=26&page=show_problem&problem=2330
——>>AC的感觉真是不错!艰辛!!!从2到N-1依次选i为裁判,求其左边有几人比裁判的等级低,记为c[i],再求右边有几人比裁判等级低,记为d[i],比赛场数为c[i]*(N-i-d[i]) + (i-1-c[i])*d[i],当然啦,求c[i]、d[i]时不可一个一个地循环扫,否则TLE。设等级存在数组a[]里,设等级标记存在数组x[],当扫到i当裁判时,该裁判的等级为a[i],等级比他低的等级有a[i]-1, a[i]-2, ...于是扫描等级数组x[],若x[j] == 1,说明等级为j的选手已存在,将前a[i]-1个x[]加起来,就是c[i],从后往前扫就可得d[i],此过程通过树状数组即二叉索引树BIT实现。要注意:c[i]*(N-i-d[i])
+ (i-1-c[i])*d[i]可能大于2147483647,所以此处应用64位整数来存。
重写:发现之前写的用了一个没有用到的x[]数组~再有,这次用printf输出64位整数,一不留意这是LA,用了%I64d错了一次,悲壮~
再用线段树:
#include <cstdio>
#include <cstring>
using namespace std;
#define lc (o<<1)
#define rc ((o<<1)|1)
const int maxn = 20000 + 10;
const int maxm = 100000;
int C[maxm<<2];
int lev[maxn], l[maxn], r[maxn];
void build(int o, int L, int R) {
C[o] = 0;
if(L == R) return;
int M = (L + R) >> 1;
build(lc, L, M);
build(rc, M+1, R);
}
void update(int o, int L, int R, int x) {
if(L == R) {
C[o]++;
return;
}
int M = (L + R) >> 1;
if(x <= M) update(lc, L, M, x);
else update(rc, M+1, R, x);
C[o] = C[lc] + C[rc];
}
int query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return C[o];
int M = (L + R) >> 1;
int ret = 0;
if(ql <= M) ret += query(lc, L, M, ql, qr);
if(qr > M) ret += query(rc, M+1, R, ql, qr);
return ret;
}
int main()
{
int T, N;
scanf("%d", &T);
while(T--) {
scanf("%d", &N);
for(int i = 1; i <= N; i++) scanf("%d", &lev[i]);
build(1, 1, maxm);
update(1, 1, maxm, lev[1]);
for(int i = 2; i < N; i++) {
l[i] = query(1, 1, maxm, 1, lev[i]);
update(1, 1, maxm, lev[i]);
}
build(1, 1, maxm);
update(1, 1, maxm, lev
);
for(int i = N-1; i > 0; i--) {
r[i] = query(1, 1, maxm, 1, lev[i]);
update(1, 1, maxm, lev[i]);
}
long long ret = 0;
for(int i = 2; i < N; i++)
ret += (long long)l[i] * (N - i - r[i]) + (long long)(i - 1 - l[i]) * r[i];
printf("%lld\n", ret);
}
return 0;
}
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=26&page=show_problem&problem=2330
——>>AC的感觉真是不错!艰辛!!!从2到N-1依次选i为裁判,求其左边有几人比裁判的等级低,记为c[i],再求右边有几人比裁判等级低,记为d[i],比赛场数为c[i]*(N-i-d[i]) + (i-1-c[i])*d[i],当然啦,求c[i]、d[i]时不可一个一个地循环扫,否则TLE。设等级存在数组a[]里,设等级标记存在数组x[],当扫到i当裁判时,该裁判的等级为a[i],等级比他低的等级有a[i]-1, a[i]-2, ...于是扫描等级数组x[],若x[j] == 1,说明等级为j的选手已存在,将前a[i]-1个x[]加起来,就是c[i],从后往前扫就可得d[i],此过程通过树状数组即二叉索引树BIT实现。要注意:c[i]*(N-i-d[i])
+ (i-1-c[i])*d[i]可能大于2147483647,所以此处应用64位整数来存。
#include <iostream> #include <string.h> using namespace std; const int maxn = 20000 + 10; //人数3 <= N <= 20000 const int maxnn = 100000 + 10; //等级 [1, 100000] int a[maxn], c[maxn], d[maxn], x[maxnn], BIT[maxnn], N; //a[i]为i的等级,c[i]为第i个人的西边等级比他低的人数,d[i]为第i个人的东边等级比他低的人数,x[i]为目前为止等级为i的人是否存在,BIT[i]为二叉索引树第i个条的长度 int lowbit(int i) //数i的二进制表示的从右边开始第一个1对应的值 { return i&-i; } int sum(int i) //BIT求x的前i项和 { int ret = 0; while(i > 0) { ret += BIT[i]; i -= lowbit(i); } return ret; } void add(int i, int d) //当修改x[i]的时候,对应修改二叉索引树中BIT数组 { while(i <= maxnn-1) //注意:这个maxnn-1千万别写成N,需要 >= 100000 因为这是对等级来说的,不是对选手来说的! { BIT[i] += d; i += lowbit(i); } } int main() { int T, i; cin>>T; while(T--) { memset(x, 0, sizeof(x)); //初始化x为0 memset(BIT, 0, sizeof(BIT)); //初始化BIT为0,因为x数组为0,无论多少个0相加还是0 cin>>N; for(i = 1; i <= N; i++) cin>>a[i]; for(i = 1; i <= N; i++) //从西往东求第i个人的西边有几个比他等级低的选手,即c[i] { c[i] = sum(a[i]-1); //求和 x[a[i]] = 1; //标记这个等级已存在 add(a[i], 1); //加到BIT去 } memset(x, 0, sizeof(x)); //再次初始化不可少! memset(BIT, 0, sizeof(BIT)); //再次初始化不可少! for(i = N; i >= 1; i--) //从东往西求第i个人的东边有几个比他等级低的选手,即d[i] { d[i] = sum(a[i]-1); //求和 x[a[i]] = 1; //标记这个等级已存在 add(a[i], 1); //加到BIT去 } long long sum = 0; //小心溢出呀!!! for(i = 2; i <= N-1; i++) sum += c[i]*(N-i-d[i]) + (i-1-c[i])*d[i]; //乘法原理与加法原理 cout<<sum<<endl; } return 0; }
重写:发现之前写的用了一个没有用到的x[]数组~再有,这次用printf输出64位整数,一不留意这是LA,用了%I64d错了一次,悲壮~
#include <cstdio> #include <cstring> using namespace std; const int maxn = 20000 + 10; const int maxv = 100000 + 10; int a[maxn], c[maxn], d[maxn], BIT[maxv]; int lowerbit(int x) { return x&-x; } int sum(int i) { int ret = 0; while(i > 0) { ret += BIT[i]; i -= lowerbit(i); } return ret; } void add(int i, int x) { while(i < maxv) { BIT[i] += x; i += lowerbit(i); } } int main() { int T, N, i; scanf("%d", &T); while(T--) { scanf("%d", &N); for(i = 1; i <= N; i++) scanf("%d", &a[i]); memset(BIT, 0, sizeof(BIT)); for(i = 1; i <= N-1; i++) { c[i] = sum(a[i]-1); add(a[i], 1); } memset(BIT, 0, sizeof(BIT)); for(i = N; i >= 2; i--) { d[i] = sum(a[i]-1); add(a[i], 1); } long long ret = 0; for(i = 2; i <= N-1; i++) ret += c[i]*(N-i-d[i]) + d[i]*(i-1-c[i]); printf("%lld\n", ret); } return 0; }
再用线段树:
#include <cstdio>
#include <cstring>
using namespace std;
#define lc (o<<1)
#define rc ((o<<1)|1)
const int maxn = 20000 + 10;
const int maxm = 100000;
int C[maxm<<2];
int lev[maxn], l[maxn], r[maxn];
void build(int o, int L, int R) {
C[o] = 0;
if(L == R) return;
int M = (L + R) >> 1;
build(lc, L, M);
build(rc, M+1, R);
}
void update(int o, int L, int R, int x) {
if(L == R) {
C[o]++;
return;
}
int M = (L + R) >> 1;
if(x <= M) update(lc, L, M, x);
else update(rc, M+1, R, x);
C[o] = C[lc] + C[rc];
}
int query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return C[o];
int M = (L + R) >> 1;
int ret = 0;
if(ql <= M) ret += query(lc, L, M, ql, qr);
if(qr > M) ret += query(rc, M+1, R, ql, qr);
return ret;
}
int main()
{
int T, N;
scanf("%d", &T);
while(T--) {
scanf("%d", &N);
for(int i = 1; i <= N; i++) scanf("%d", &lev[i]);
build(1, 1, maxm);
update(1, 1, maxm, lev[1]);
for(int i = 2; i < N; i++) {
l[i] = query(1, 1, maxm, 1, lev[i]);
update(1, 1, maxm, lev[i]);
}
build(1, 1, maxm);
update(1, 1, maxm, lev
);
for(int i = N-1; i > 0; i--) {
r[i] = query(1, 1, maxm, 1, lev[i]);
update(1, 1, maxm, lev[i]);
}
long long ret = 0;
for(int i = 2; i < N; i++)
ret += (long long)l[i] * (N - i - r[i]) + (long long)(i - 1 - l[i]) * r[i];
printf("%lld\n", ret);
}
return 0;
}
相关文章推荐
- LA 4329(p197)----Ping pong
- LA 4329 - Ping pong 树状数组(Fenwick树)
- LA 4329 - Ping pong 树状数组(Fenwick树)
- LA 4329 Ping pong [树状数组]
- 树状数组(LA4329,UVaLive4329,Ping pong)
- LA 4329 Ping pong
- LA 4329 Ping pong 树状数组
- LA 4329 - Ping pong 树状数组
- LA 4329 Ping pong
- LA 4329 Ping pong
- LA 4329 - Ping pong(树状数组)
- LA 4329 Ping Pong 2008 北京区域赛 H , BIT 二叉索引树(树状数组)的应用
- LA 4329 Ping pong
- LA 4329 Ping Pong 2008 北京区域赛 H , BIT 二叉索引树(树状数组)的应用
- LA-4329 Ping pong - treap (排名树)/树状数组求排名
- LA - 4329 - Ping pong
- LA 4329 Ping Pong 2008 北京区域赛 H , BIT 二叉索引树(树状数组)的应用
- LA 4329 Ping pong乒乓比赛【树状数组】
- Beijing 2008 树状数组 ,LA 4329 Ping pong
- LA 4329 - Ping pong