题目描述
有n位骑士想要通过淘汰赛决出他们当中最强大的一个。所有的骑士由1到n编号,他们总共进行了m场比赛,在第i场比赛中,所有编号在li到ri之间且尚未出局的骑士进行了一场比赛,决出了获胜者xi,其他参加比赛的骑士就出局了;我们称这些骑士被骑士xi打败了。m场比赛过后,只有一位骑士还没有出局,他就是最终的获胜者,我们希望知道其他所有骑士分别是被谁打败了。
输入
第一行包含两个正整数n和m,表示骑士和比赛的数量。
接下来m行,每行三个数l,r和x,表示参与比赛的骑士编号范围,以及获胜者的编号。
输出
输出n个由空格分隔的整数,第i个表示打败骑士i的骑士的编号。如果骑士i是获胜者,就在对应位置输出0。
样例输入
5 3
2 4 3
1 3 1
1 5 5
样例输出
5 3 1 3 0
提示
第一场比赛中,骑士3打败了骑士2和4。 第二场比赛中,骑士1打败了骑士3。 第三场比赛中,骑士5打败了骑士1。 最终的胜利者是骑士5。
对于30%的数据,n ≤ 1000;
对于100%的数据,1 ≤ m < n ≤ 3×106, 1 ≤ l ≤ x ≤ r ≤ n,保证l到r之间至少有两位尚未出局的骑士,且骑士x一定尚未出局。
分析:每次一定只剩下一个人,所以从最后一次比赛开始处理,用本轮除去x点的比赛区间去覆盖一次。用线段树处理不会超时。
也可以用链表维护。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<math.h>
#define maxn 3000000+5
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;
struct node
{
int l,r,x;
}e[maxn];
int n,m,add[maxn];
int sum[maxn<<2];
void pushup(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];}
void pushdown(int rt,int ln,int rn)
{
if(add[rt])
{
add[rt<<1]=1;
add[rt<<1|1]=1;
sum[rt<<1]=sum[rt];
sum[rt<<1|1]=sum[rt];
add[rt]=0;
}
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(L<=l && r<=R)
{
sum[rt]=C;
add[rt]=1;
return;
}
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
if(L<=m) update(L,R,C,l,m,rt<<1);
if(R>m) update(L,R,C,m+1,r,rt<<1|1);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(l==r)
{
return sum[rt];
}
int m=(l+r)>>1;
pushdown(rt,m-l+1,r-m);
int ans=0;
if(L<=m) ans=query(L,R,l,m,rt<<1);
if(R>m) ans=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].x);
if(e[i].l>e[i].r)
swap(e[i].l,e[i].r);
}
for(i=m;i>=1;i--)
{
if(e[i].l<e[i].x) update(e[i].l,e[i].x-1,e[i].x,1,n,1);
if(e[i].r>e[i].x) update(e[i].x+1,e[i].r,e[i].x,1,n,1);
}
printf("%d",query(1,1,1,n,1));
for(i=2;i<=n;i++)
printf(" %d",query(i,i,1,n,1));
printf("\n");
return 0;
}