Codeforces Round #207 (Div. 2) C - Knight Tournament

這題有三種做法,通常做法是線段樹,當你熟悉STL可以用set做,但有更牛的優化做法,在空間上完虐前兩種。

題意:輸入n和m,代表n個騎士和m場對決,每個騎士的編號從1~n,每個對決會給出l,r,x表示從l到r這區間的所有人蔘加這場對決,勝者爲x,輸的人輸出第一次敗給哪個騎士編號,最後只有一個勝者勝者輸出0.

思路:正如之前所說,直接用線段樹更新區間,然後詢問即可。

代碼如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
struct Node
{
  int l,r,value;
}tree[1200005];
void bulid(int v,int l,int r)
{
  tree[v].l=l;
  tree[v].r=r;
  if(l==r)
  {
    tree[v].value=0;
    return;
  }
  int mid=(l+r)/2;
  bulid(v*2,l,mid);
  bulid(v*2+1,mid+1,r);
  tree[v].value=tree[v*2].value+tree[v*2+1].value;
}
void update(int v,int l,int r,int m)
{
  if(tree[v].l==l&&tree[v].r==r)
  {
    if(tree[v].value==0)
      tree[v].value=m;
    return;
  }
  if(tree[v].value) return;
  int mid=(tree[v].l+tree[v].r)/2;
  if(r<=mid)
    update(v*2,l,r,m);
  else
  {
    if(l>mid)
      update(v*2+1,l,r,m);
    else
    {
      update(v*2,l,mid,m);
      update(v*2+1,mid+1,r,m);
    }
  }
}
int ans;
void query(int v,int m)
{
  if(tree[v].value) ans=tree[v].value;
  if(tree[v].l==m&&tree[v].r==m) return;
  int mid=(tree[v].l+tree[v].r)/2;
  if(m<=mid) query(v*2,m);
  else query(v*2+1,m);
}
int L[300005],R[300005],X[300005];
int main()
{
  int n,m,l,r,x;
  while(~scanf("%d%d",&n,&m))
  {
    bulid(1,1,n);
    for(int i=0;i<m;i++)
      scanf("%d%d%d",&L[i],&R[i],&X[i]);
    for(int i=0;i<m;i++)
    {
      int a,b;
      a=L[i],b=X[i]-1;
      if(b>=a)
      {
        update(1,a,b,X[i]);
      }
      a=X[i]+1;b=R[i];
      if(a<=b)
      {
        update(1,a,b,X[i]);
      }
    }
    for(int i=1;i<n;i++)
    {
      ans=0;query(1,i);
      printf("%d ",ans);
    }
    ans=0;query(1,n);
    printf("%d\n",ans);
  }
}
STL採用set容器每次對決輸入用earse函數刪除區間【l,r】再把x用insert插入回去。

代碼如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
set<int>s;
int a[300005];
int main()
{
  int n,m,x,y,z;
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)
    s.insert(i);
  set<int>::iterator l,r,it;
  memset(a,0,sizeof(a));
  for(int i=0;i<m;i++)
  {
    scanf("%d%d%d",&x,&y,&z);
    l=s.lower_bound(x);
    r=s.upper_bound(y);
    for(it=l;it!=r;it++)
    {
      if(*it!=z)
        a[*it]=z;
    }
    s.erase(l,r);s.insert(z);
  }
  for(int i=1;i<=n;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
}
借鑑別人的優化做法,就是有點難想,理解起來需要花點時間

代碼如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
int ans[300005],p[300005];
int getl(int x)
{
  int i=x,j;
  while(x!=p[x])
    x=p[x];
  while(i!=p[i])
  {
    j=p[i];
    p[i]=x;
    i=j;
  }
  return x;
}
int main()
{
  int n,m,l,r,x;
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n+1;i++) p[i]=i;
  for(int i=0;i<m;i++)
  {
    scanf("%d%d%d",&l,&r,&x);
    int j=getl(l);
    while(j<=r)
    {
      if(j!=x)
      {
        ans[j]=x;p[j]=j+1;
      }
      j++;
      j=getl(j);
    }
  }
  for(int i=1;i<n;i++)
  {
    printf("%d ",ans[i]);
  }
  printf("%d\n",ans[n]);
}




發佈了56 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章