CodeForces - 357C C - Knight Tournament 并查集or set模拟

Hooray! Berl II, the king of Berland is making a knight tournament. The king has already sent the message to all knights in the kingdom and they in turn agreed to participate in this grand event.

As for you, you're just a simple peasant. There's no surprise that you slept in this morning and were late for the tournament (it was a weekend, after all). Now you are really curious about the results of the tournament. This time the tournament in Berland went as follows:

  • There are n knights participating in the tournament. Each knight was assigned his unique number — an integer from 1 to n.
  • The tournament consisted of m fights, in the i-th fight the knights that were still in the game with numbers at least li and at most ri have fought for the right to continue taking part in the tournament.
  • After the i-th fight among all participants of the fight only one knight won — the knight number xi, he continued participating in the tournament. Other knights left the tournament.
  • The winner of the last (the m-th) fight (the knight number xm) became the winner of the tournament.

You fished out all the information about the fights from your friends. Now for each knight you want to know the name of the knight he was conquered by. We think that the knight number b was conquered by the knight number a, if there was a fight with both of these knights present and the winner was the knight number a.

Write the code that calculates for each knight, the name of the knight that beat him.

Input

The first line contains two integers nm (2 ≤ n ≤ 3·105; 1 ≤ m ≤ 3·105) — the number of knights and the number of fights. Each of the following m lines contains three integers li, ri, xi (1 ≤ li < ri ≤ nli ≤ xi ≤ ri) — the description of the i-th fight.

It is guaranteed that the input is correct and matches the problem statement. It is guaranteed that at least two knights took part in each battle.

Output

Print n integers. If the i-th knight lost, then the i-th number should equal the number of the knight that beat the knight number i. If the i-th knight is the winner, then the i-th number must equal 0.

Example
Input
4 3
1 2 1
1 3 3
1 4 4
Output
3 1 4 0 
Input
8 4
3 5 4
3 7 6
2 8 8
1 8 1
Output
0 8 4 6 4 8 6 1 
Note

Consider the first test case. Knights 1 and 2 fought the first fight and knight 1 won. Knights 1 and 3 fought the second fight and knight 3 won. The last fight was between knights 3 and 4, knight 4 won.

题意:第一行输入n,m,n表示有n个人(标号1~n),m表示有m 场战斗,接下来m行,每行输入l , r , x  ,表示标号从l 到 r的人进行了一场战斗,其中x (l<=x<=r) 为最后的胜利者,即x杀死了该场战斗中的其它人,那么在下一场 战斗中死了的人不再进入战斗;要求输出杀死每一个人的直接凶手的标号,最后活着的那个人的输出标号为0;

思路:这个题我看网上大牛们有两种方法做的

1、set函数来模拟,好比区间染色问题,不能染自己和已经被染得,用到STL中的函数;

http://blog.csdn.net/howardemily/article/details/53573427


#include
#define N 3e5+7
using namespace std;
setst;
set::iterator ib,ie,is;
int ans[300005];
int main()
{     int n,m,a,b,x,i;
      while(cin>>n>>m)
      {    for(i=1;i<=n;i++)
            st.insert(i);//set函数中元素不会重复插入且有序,这里将所有人的编号插入
            memset(ans,0,sizeof(ans));
while(m--)
{     cin>>a>>b>>x;
     is=ib=st.lower_bound(a);
     ie=st.lower_bound(b+1);
 for(ib;ib!=ie;ib++)
  {  if((*ib)!=x&&!ans[*ib])
      {   ans[*ib]=x;
  }
      
  }
  st.erase(is,ie);//删除区间
  st.insert(x);//再将胜利者插入;
}
cout<for(i=2;i<=n;i++)
 cout<<' '< cout< }
 return 0;
}

2、并查集

  因为如果不用STL的话普通的暴力模拟会在11就超时,所以我们这里也可以考虑并查集,当 find(l)==

find(r)时我们就表示整个区间都被更新过了,就需要跳过这个区间去找下一个区间的就好,那么对于这里显然我们在合并的时候肯定要将数值大的一个点做为祖先,也就是区间最右边的点,这样当该点被更新完后才能找到它最右边的未被更新过的点,并且当给定的区间中包含已经更新过的部分区间那么我们就可以通过其祖先直接找到最右边未被更新过的区间.时间复杂度就会降下来了

#include
#include
#include
#include
#include
#define N 100010*3
using namespace std;
int pre[N];
int ans[N];
int n,m;
void build()
{    for(int i=1;i<=n;i++)
      pre[i]=i;
      return ;
}
int find(int x)
{   if(x==pre[x])
    return x;
    else
    return pre[x]=find(pre[x]);
}
void join(int x1,int x2)
{    int f1=find(x1);
     int f2=find(x2);
     if(x1>x2)
     pre[f2]=f1;
     else
     pre[f1]=f2;
     return ;
}
int main()
{      int i,a,b,x;
       while(cin>>n>>m)
       {   build();
           memset(ans,0,sizeof(ans));
           while(m--)
           {   
     cin>>a>>b>>x;
              if(find(a)==find(b))
              continue;
              else
               for(i=a;i<=b;i=find(i)+1)
               {     if(i==x)
//胜利者要跳过
                     continue;
                     if(ans[i]==0)
                     ans[i]=x;
                     if(i!=1)
                     join(i,i-1);
  }
  }
  cout<
  for(i=2;i<=n;i++)
  cout<<' '<
  cout<
  }
  return 0;
}



你可能感兴趣的:(并查集,思维)