HDU 2492 Ping pong 解题报告(线段树)
两棵线段树。
首先,分析一下问题。题目让我们找出所有的 排名以及位置 都在两个乒乓球家之间的所有组合。
两个区间,首先想到的是二维。。。(因为昨天刚刚搞了一个二维)。
发现这种数据是一维的,所以解法一定也是一维。不过又不是普通的一维。。。呵呵,吹水了
我们枚举所有的乒乓球家。找出 他左边的排名比他低的,记为num1,以及右边的排名比他高的,记为num2,那么由他主持的比赛就有num1*num2+(左边人数-num1)*(右边人数-num2)。加起来,就是结果了。
因为我们是枚举,所有可以动态的完成树的更新。每次将取出第 i 个乒乓球家,在右边的树里将他删除,查询比他排名高的,在左边的树里查询比他排名低的,计算他主持的比赛数之后,将他加入左边的树。
只有20次查询,复杂度为 n*log n,基本可以接受。以下代码在杭电上的时效为:625MS
#include <iostream> using namespace std; #define rect 1,100000,1 #define defm int m=(l+r)>>1; #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 const int maxn=131073; int sum[2][maxn<<1]; int height[20001]; int treeNO; void updateFather(int pos) { sum[treeNO][pos]=sum[treeNO][pos<<1]+sum[treeNO][pos<<1|1]; } void update(int p,int flag,int l,int r,int pos) { if(l==r) { sum[treeNO][pos]+=flag; return; } defm; if(p<=m) update(p,flag,lson); else update(p,flag,rson); updateFather(pos); } int query(int L,int R,int l,int r,int pos) { if(L<=l && r<=R) return sum[treeNO][pos]; defm; return (L<=m?query(L,R,lson):0)+(m<R?query(L,R,rson):0); } int main() { int T,n,ll,rl; long long ans; scanf("%d",&T); while(T--) { ans=0; memset(sum,0,sizeof(sum)); scanf("%d",&n); treeNO=0; for(int i=1;i<=n;i++) { scanf("%d",height+i); update(height[i],1,rect); } for(int i=1;i<n;i++) { treeNO=0; update(height[i],-1,rect); rl=query(1,height[i],rect); treeNO=1; ll=query(1,height[i],rect); ans+=(long long)ll*(n-i-rl)+(long long)(i-1-ll)*rl; update(height[i],1,rect); } printf("%I64d\n",ans); } }
借鉴了网上其他大牛的解题报告,我们可以做如下优化:
每次我们要求的是 i 左边比 i 排名低的数,以及右边比 i 排名高的数。我们可以在输入数据时将所有的 比 i 排名低的记录到数组里。然后反向遍历,求出所有右边的比 i 高的放到数组里。再循环求解即可。仍然用线段树实现,时效453MS
#include <iostream> using namespace std; #define rect 1,100000,1 #define defm int m=(l+r)>>1; #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 const int maxn=131073; int sum[maxn<<1]; int height[20001]; int ll[20001]; int rl[20001]; void updateFather(int pos) { sum[pos]=sum[pos<<1]+sum[pos<<1|1]; } void update(int p,int l,int r,int pos) { if(l==r) { sum[pos]++; return; } defm; if(p<=m) update(p,lson); else update(p,rson); updateFather(pos); } int query(int L,int R,int l,int r,int pos) { if(L<=l && r<=R) return sum[pos]; defm; return (L<=m?query(L,R,lson):0)+(m<R?query(L,R,rson):0); } int main() { // freopen("in.txt","r",stdin); int T,n; long long ans; scanf("%d",&T); while(T--) { ans=0; memset(sum,0,sizeof(sum)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",height+i); ll[i]=query(1,height[i],rect); update(height[i],rect); } memset(sum,0,sizeof(sum)); for(int i=n;i;i--) { rl[i]=query(1,height[i],rect); update(height[i],rect); } for(int i=2;i<n;i++) ans+=(long long)ll[i]*(n-i-rl[i])+(long long)(i-1-ll[i])*rl[i]; printf("%I64d\n",ans); } }