题目链接:http://codeforces.com/problemset/problem/356/A
题意:给n个人和m次决斗,每次决斗表示 [ l , r ] 区间内的每人都被 x 打败,最后输出每个人被谁打败,最后的赢家输出0。
思路:这一题有3e5个人和3e5次决斗,直接暴力一遍一定会超时,所以可以考虑用区间合并的思想来做这道题。首先开两个一维数组,f[] 数组用来存答案,Next[]数组来实现区间合并。初始化时f[i] = i , Next[i] = i+1;
之后就是关键的区间合并啦。
每当我们读入一组 l , r , x 时,我们把[ l , r ]分成两段 [l , x-1] 和 [x , r];
然后用for循环每次更新 f[i] 和 Next[i] ,左侧Next[i] = x , 右侧Next[i] = Next[r];
用 i = Next[i] 来跳过已经更新过 f[i] 的点。
如果还不是很理解的话,我建议读者可以用两个区间来模拟一下 Next[] 数组值的变化。
毕竟我语言功底较差,望见谅。
具体代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=3e5+7;
int f[maxn],Next[maxn],vis[maxn];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
//初始化
for(int i=1; i<=n; i++)
{
f[i]=i;
Next[i]=i+1;
vis[i]=0;
}
while(m--)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
//更新左侧
for(int i=l; i<x;)
{
if(vis[i]==0&&i!=x)
{
vis[i]=1;
f[i]=x;
}
int t=i;
i=Next[i];
Next[t]=x;
}
//更新右侧
for(int i=x; i<=r;)
{
if(vis[i]==0&&i!=x)
{
vis[i]=1;
f[i]=x;
}
int t=i;
i=Next[i];
Next[t]=Next[r];
}
}
for(int i=1; i<=n; i++)
{
if(i!=1) printf(" ");
if(f[i]==i) printf("0");
else printf("%d",f[i]);
}
puts("");
}
return 0;
}