E. Two Teams(线段树+链表)

Posted letlifestop

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Two Teams(线段树+链表)相关的知识,希望对你有一定的参考价值。

 题目链接:

https://codeforces.com/problemset/problem/1154/E

题目大意:

给你n个人和间隔k,两个教练从里面选人。每一次教练选出这个区间里面权值最大的那个学生,然后这个学生往左k个,往右k个,都是这个教练的学生。选完的学生会退出,然后剩余的学生自动补齐。然后问你每一个学生的教练是谁?

具体思路:

一开始没有注意到时自动补齐的,打了一个线段树区间覆盖,wa4

对于这个自动补全,我们可以建立一个链表的形式,保存这个点前面的学生是谁,后面的学生是谁

然后每一次寻找这个区间里面最大的学生编号是哪个,然后这个学生往左往右k个都是当前的教练学生。TLE在37

继续改进,发现有更新操作,也就是说我们可以通过直接判断tree[1]的值就知道当前这个区间里面最大的权值是哪个。然后打一个映射就知道这个学生的编号了,注意指针的跳动。

AC代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 # define ll long long
  4 # define inf 0x3f3f3f3f
  5 # define lson l,mid,rt<<1
  6 # define rson mid+1,r,rt<<1|1
  7 const int maxn = 2e5+100;
  8 int pre[maxn],nex[maxn];
  9 int a[maxn];
 10 int tree[maxn<<2];
 11 int lazy[maxn<<2];
 12 void down(int rt)
 13 {
 14     if(lazy[rt])
 15     {
 16         tree[rt<<1]=0;
 17         tree[rt<<1|1]=0;
 18         lazy[rt<<1]=1;
 19         lazy[rt<<1|1]=1;
 20         lazy[rt]=0;
 21     }
 22 }
 23 void up(int rt)
 24 {
 25     tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
 26 }
 27 void build(int l,int r,int rt)
 28 {
 29     if(l==r)
 30     {
 31         tree[rt]=a[l];
 32         return ;
 33     }
 34     int mid=l+r>>1;
 35     build(lson);
 36     build(rson);
 37     up(rt);
 38 }
 39 int ans[maxn];
 40 int maxx,id;
 41 int pos[maxn];
 42 //void  ask(int l,int r,int rt)
 43 //{
 44 //    if(tree[rt]<maxx)
 45 //        return ;
 46 //    if(tree[rt]>maxx)
 47 //    {
 48 //        maxx=tree[rt];
 49 //    }
 50 //    int mid=l+r>>1;
 51 //    down(rt);
 52 //    if(l<=mid)
 53 //    ask(lson);
 54 //    if(r>mid)
 55 //    ask(rson);
 56 //    up(rt);
 57 //}
 58 void update(int l,int r,int rt,int L,int R)
 59 {
 60     if(L<=l&&R>=r)
 61     {
 62         lazy[rt]=1;
 63         tree[rt]=0;
 64         return ;
 65     }
 66     down(rt);
 67     int mid=l+r>>1;
 68     if(L<=mid)
 69         update(lson,L,R);
 70     if(R>mid)
 71         update(rson,L,R);
 72     up(rt);
 73 }
 74 int main()
 75 {
 76     int n,k;
 77     scanf("%d %d",&n,&k);
 78     for(int i=1; i<=n; i++)
 79     {
 80         scanf("%d",&a[i]);
 81         pre[i]=i-1;
 82         nex[i]=i+1;
 83         pos[a[i]]=i;
 84     //cout<<1<<endl;
 85     }
 86     build(1,n,1);
 87     int flag=1,type=1;
 88     while(flag)
 89     {
 90         maxx=tree[1];
 91 //        ask(1,n,1);
 92         if(!maxx)
 93             break;
 94         id= pos[maxx];
 95         ans[id]=type;
 96         //  cout<<id<<" ";
 97         int tmp_l=id;
 98         for(int i=1; i<=k; i++)
 99         {
100             if(pre[tmp_l]==0)
101                 break;
102             ans[pre[tmp_l]]=type;
103             //  cout<<pre[tmp_l]<<" ";
104             tmp_l=pre[tmp_l];
105         }
106         int  tmp_r=id;
107         for(int i=1; i<=k; i++)
108         {
109             if(nex[tmp_r]==n+1)
110                 break;
111             ans[nex[tmp_r]]=type;
112             //    cout<<pre[tmp_l]<<" ";
113             tmp_r=nex[tmp_r];
114         }
115         update(1,n,1,tmp_l,tmp_r);
116         int tmp1=nex[tmp_r];
117         int tmp2=pre[tmp_l];
118         pre[tmp1]=tmp2;
119         nex[tmp2]=tmp1;
120         type=(type==1?2:1);
121     }
122     for(int i=1; i<=n; i++)
123     {
124         printf("%d",ans[i]);
125     }
126     printf("\n");
127     return 0;
128 }

 

以上是关于E. Two Teams(线段树+链表)的主要内容,如果未能解决你的问题,请参考以下文章

E. Boring Segments(尺取&线段树)

Codeforces 292 E. Copying Data (线段树)

CodeForces915 E. Physical Education Lessons 线段树

Codeforces Round #603 (Div. 2) E. Editor 线段树

Codeforces1555 E. Boring Segments(尺取+线段树)

Codeforces Round #603 (Div. 2) E. Editor(线段树)