华山论剑
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
有n个剑客(编号1~n)相约华山比剑,分 m 次决斗,为了节省时间,每次决斗 编号在[l,r]的剑客一起决斗,然后xi获胜。当进行下一次决斗,失败后的剑客可能再参与到决斗,m 次决斗后可能不止一位获胜者(没有失败过就视为获胜者)。
输入
多组测试数据。
对于每组测试数据,第一行输入n和m。接下来输入m行,每行输入l,r,xi。
2 ≤ n ≤ 3*10^5; 1 ≤ m ≤ 3*10^5,l ≤ xi ≤ r
输出
每组测试数据输出n个数字,数字间用空格隔开。第i个数子表示第一次击败i号剑客的剑客编号,若i号剑客是最后的获胜者,输出0;
样例输入
3 2
1 2 2
1 3 2
样例输出
2 0 2
问题分析:线段树的区间修改,第一次写线段树,还不是很懂,注意cin会超时
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn = 301000;
int record[maxn * 5],win[maxn]; //record用来记录标记是否有获胜者,0表示有获胜者(以二叉树的数组在存储),win来记录获胜者
int m,n,u,v,w;
void Update(int l,int r,int index,int ll,int rr)
{
// 说明在此区间有赢家了,已经比试过,退出
if (record[index])
return ;
if (l == r)
{
if (record[index] == 0 && l == ll && l != w) // 已经到达叶子结点,若该人不是赢家,则是输家
{
record[index] = 0;
win[l] = w;
}
return ;
}
int mid = (l + r) >> 1;
// 折半查询
if (rr <= mid)
Update(l,mid,index*2,ll,rr);
else if (ll > mid)
Update(mid+1,r,index*2+1,ll,rr);
else//区间交叉
{
Update(l,mid,index*2,ll,mid);
Update(mid+1,r,index*2+1,mid+1,rr);
}
//向父节点更新
record[index] = record[index*2] && record[index*2+1];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(record,0,sizeof(record));
memset(win,0,sizeof(win));
while(m--)
{
scanf("%d%d%d",&u,&v,&w); // cin要超时
Update(1,n,1,u,v);
}
for(int i=1; i<=n; i++)
printf("%d%c",win[i],i==n?10:32);
}
return 0;
}