数据结构(脑洞题,BIT):COGS 2394. 比赛
比赛
时间限制:1 s 内存限制:256 MB
【题目描述】
n(n≤100000)个人编号为0到n-1,每人都有一个能力值,大小在0到n-1之间,各不相同,他们之间有c场比赛,每场比赛指定一个区间 [l,r],当前第l个到第r个中能力值最大的获胜,其他的都被淘汰,不再出现在候选之列,现在你是n个人中的一个,也要参加这比赛,但你可以选择已经排 好的n-1人之间的n个位置中的一个进行插入,使得自己赢的场数最多,输出最小的位置。
【输入格式】
第一行三个数n c k,k是你的能力值。
接下来n-1行表示前n-1个人的能力值。
最后c行表示比赛,保证比赛合法。
【输出格式】
一行即答案。
【样例输入】
5 3 3
1
0
2
4
1 3
0 1
0 1
【样例输出】
1
这道题,发现对于一个比赛,求出其实际上对应的人分别是哪些,假想每个人自己一个人比赛一次,再考虑对于比赛建树,一个A节点是另一个节点B的子节点仅当A的最强者参加了比赛B,维护胜利者的能力值。假设要参加某场比赛,那么发现这场比赛中最后一个人被挤出去了,所以对于树中节点不统计最后那个人的信息,但在整合子树时考虑。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=200010; 6 int bit[maxn],N,fa[maxn]; 7 int a[maxn],Max[maxn]; 8 int ID[maxn],dp[maxn]; 9 int L[maxn],R[maxn]; 10 int n,c,k; 11 12 void Add(int x,int d){ 13 while(x<=N){ 14 bit[x]+=d; 15 x+=x&(-x); 16 } 17 } 18 19 int Pos(int k){ 20 int p=0; 21 for(int i=N;i;i>>=1) 22 if(bit[p+(i>>1)]<k) 23 k-=bit[p+=i>>1]; 24 return p+1; 25 } 26 27 int main(){ 28 freopen("competition.in","r",stdin); 29 freopen("competition.out","w",stdout); 30 scanf("%d%d%d",&n,&c,&k); 31 for(N=1;N<=n;N<<=1); 32 for(int i=1;i<n;i++){ 33 scanf("%d",&a[i]); 34 Add(i,1);ID[i]=i; 35 L[i]=R[i]=i; 36 }Add(n+1,1); 37 for(int i=1,l,r;i<=c;i++){ 38 scanf("%d%d",&l,&r);l++,r++; 39 L[n+i]=Pos(l);R[n+i]=Pos(r+1)-1; 40 for(int j=l;j<=r;j++){ 41 int x=ID[Pos(j)];fa[x]=n+i; 42 Max[n+i]=max(Max[n+i],Max[x]); 43 if(j!=r)Max[n+i]=max(Max[n+i],a[R[x]]); 44 } 45 ID[L[n+i]]=n+i; 46 for(int j=r;j>l;j--) 47 Add(Pos(j),-1); 48 } 49 50 for(int i=c;i>=1;i--) 51 dp[n+i]=Max[n+i]<k?dp[fa[n+i]]+1:0; 52 53 int M=0,p=1; 54 for(int i=1;i<=n;i++) 55 if(dp[fa[i]]>M) 56 M=dp[fa[i]],p=i; 57 printf("%d\n",p-1); 58 return 0; 59 }
尽最大的努力,做最好的自己!