题目https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=26&problem=2330&mosmsg=Submission+received+with+ID+1779597
题意:
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个能力值a[i]。每场比赛需要三个人:两名选手,一名裁判。他们有个奇怪的约
定,裁判必须住在两名选手之间,而裁判的能力值也必须在两名选手之间。问一共能组织多少种比赛。
枚举2-n-1 ai为裁判时, 假设a1~a(i-1)中有ci个比ai小的数, a(i+1)~an中有di个比ai小的数
那么比赛次数 为 ci*(n-i-di) + (i-1-ci)*di
所以把2~n-1的情况都枚举求和就好了
两种做法求ci:
第一种排名树:
对于求ci..我是用treap实现的排名树来求得:
开两个treap, treap1先储存好a1~an
然后把a1插入treap2
for (i=2;i<=n;i++)
{
把ai插入treap2,求出treap2中 ai的排名 ,显然 排名减1就是比ai小的数的个数,也就是我们要求的ci (a1~a(i-1)中比ai小的数的个数)
再在treap1中求ai的排名,显然排名减1得到的是所有比ai小的数的个数,再减去ci,便得到di ( a(i+1)~an中比ai小的数的个数 )
}
for里面每次操作是logn的,因此复杂度也就是nlogn
后来试着用int交了一下是wa。。必须longlong ,LA不支持int64
-
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; #include <iostream> using namespace std; #define MAXN 20005 struct data{ long long l,r,v,size,rnd,w; }; class tp { public: long long n,size,root,ans; tp() { n=size=root=ans=0; } data tr[MAXN]; void update(long long k)//更新结点信息 { tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w; } void rturn(long long &k) { long long t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k; tr[t].size=tr[k].size;update(k);k=t; } void lturn(long long &k) { long long t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k; tr[t].size=tr[k].size;update(k);k=t; } void insert(long long &k,long long x) { if(k==0) { size++;k=size; tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand(); return; } tr[k].size++; if(tr[k].v==x)tr[k].w++;//每个结点顺便记录下与该节点相同值的数的个数 else if(x>tr[k].v) { insert(tr[k].r,x); if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);//维护堆性质 } else { insert(tr[k].l,x); if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k); } } long long query_rank(long long k,long long x) { if(k==0)return 0; if(tr[k].v==x)return tr[tr[k].l].size+1; else if(x>tr[k].v) return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x); else return query_rank(tr[k].l,x); } }; tp sp; tp sp2; long long tm[MAXN]; long long c[MAXN],d[MAXN]; int main() { long long t; scanf("%lld",&t); while (t--) { long long n; memset(sp.tr,0,sizeof(sp.tr)); memset(sp2.tr,0,sizeof(sp2.tr)); sp.n=sp.size=sp.root=sp.ans=0; sp2.n=sp2.size=sp2.root=sp2.ans=0; scanf("%lld",&n); long long i; for( i = 1; i <= n; i++) { scanf("%lld",&tm[i]); sp.insert(sp.root,tm[i]); } sp2.insert(sp2.root,tm[1]); for( i = 2; i <= n; i++) { sp2.insert(sp2.root,tm[i]); long long tmp=sp2.query_rank(sp2.root,tm[i]); c[i]=tmp-1; tmp=sp.query_rank(sp.root,tm[i]); d[i]=tmp-1-c[i]; } long long sum=0; for (i=2;i<=n-1;i++) { sum+=c[i]*(n-i-d[i])+d[i]*(i-1-c[i]); } printf("%lld\n",sum); } return 0; }
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; #include <iostream> using namespace std; #define MAXN 20005 const int up=100005; int tm[MAXN]; int c[MAXN],d[MAXN]; int tree[up]; int lowbit(int x) { return x&-x; } void add(int x,int value) { for (int i=x;i<=up;i=i+lowbit(i)) { tree[i]+=value; } } int get(int x) { int sum=0; for (int i=x;i;i-=lowbit(i)) { sum+=tree[i]; } return sum; } int main() { int t; scanf("%d",&t); while (t--) { int n; scanf("%d",&n); int i; for( i = 1; i <= n; i++) { scanf("%d",&tm[i]); } memset(tree,0,sizeof(tree)); for( i = 1; i <= n; i++) { add(tm[i],1); c[i]=get(tm[i]-1); } memset(tree,0,sizeof(tree)); for( i = n; i>=1; i--) { add(tm[i],1); d[i]=get(tm[i]-1); } long long sum=0; for (i=2;i<=n-1;i++) { sum+=c[i]*(n-i-d[i])+d[i]*(i-1-c[i]); } printf("%lld\n",sum); } return 0; }