Codeforces Round #424 (Div. 2) E. Cards Sorting(线段树)

题目链接:Codeforces Round #424 (Div. 2) E. Cards Sorting

题意:

将n个数放进一个队列,每次检查队首,看看是不是队列中最小的数,如果是就扔掉,如果不是就放到队尾。

这样直到队列为空,为需要操作多少次。

题解:

考虑用两个指针模拟,最开始now指针指向第一个数,然后nxt指针指向下一个将要被删除的数。

然后我们要算出这里需要移动多少步,然后删掉这个数,一直重复操作,直到将全部的数删完。

nxt指针可以用set来维护,now指针可以用并查集来维护。

计算now指针到nxt指针需要移动多少步,可以用线段树或者splay来维护。

线段树版本:

 1 #include<bits/stdc++.h>
 2 #define RT(l,r) (l+r|l!=r)
 3 #define F(i,a,b) for(int i=a;i<=b;++i)
 4 using namespace std;
 5
 6 const int N=1e6+7;
 7 int n,now,f[N],cnt,x,sum[N*2];
 8 struct node
 9 {
10     int x,idx;
11     bool operator <(const node &b)const{return x!=b.x?x<b.x:idx<b.idx;}
12 };
13 set<node>st;
14 set<node>::iterator it;
15
16 int find(int x){return f[x]!=x?f[x]=find(f[x]):x;}
17
18 int getnxt()
19 {
20     int X=st.begin()->x;
21     it=st.lower_bound({X,now});
22     if(it==st.end()||it->x > X)
23         it=st.lower_bound({X,1});
24     int tmp=it->idx;
25     st.erase(it);
26     return tmp;
27 }
28
29 void update(int pos,int v,int l=1,int r=n)
30 {
31     int rt=RT(l,r),m=l+r>>1;
32     if(l==r){sum[rt]+=v;return;}
33     if(pos<=m)update(pos,v,l,m);
34     else update(pos,v,m+1,r);
35     sum[rt]=sum[RT(l,m)]+sum[RT(m+1,r)];
36 }
37
38 int query(int L,int R,int l=1,int r=n)
39 {
40     int rt=RT(l,r),m=l+r>>1,an=0;
41     if(L<=l&&r<=R)return sum[rt];
42     if(L<=m)an+=query(L,R,l,m);
43     if(R>m)an+=query(L,R,m+1,r);
44     return an;
45 }
46
47
48 int ask(int a,int b)
49 {
50     if(a<=b)return query(a,b);
51     else return query(a,n)+query(1,b);
52 }
53
54 int main()
55 {
56     scanf("%d",&n);
57     F(i,1,n)
58     {
59         scanf("%d",&x),f[i]=i;
60         st.insert({x,i}),update(i,1);
61     }
62     now=1,cnt=1;
63     long long ans=0;
64     while(cnt<=n)
65     {
66         int nxt=getnxt();
67         ans+=ask(now,nxt);
68         if(nxt<n)f[nxt]=nxt+1;else f[nxt]=1;
69         if(cnt<n)now=find(nxt);
70         update(nxt,-1);
71         cnt++;
72     }
73     printf("%lld\n",ans);
74     return 0;
75 }

splay版本:

  1 #include<bits/stdc++.h>
  2 #define F(i,a,b) for(int i=a;i<=b;++i)
  3 using namespace std;
  4 const int N=1e6+7;
  5 int _t;
  6 struct Splay_tree
  7 {
  8     int root,q[N];
  9     int key[N],sz[N],f[N],ch[N][2],add[N];
 10     void init(){root=_t=0;}//初始化为一棵空树
 11     inline void nw(int &x,int val,int fa)
 12     {
 13         x=++_t,key[x]=val,f[x]=fa,sz[x]=1;
 14         ch[x][0]=ch[x][1]=0;
 15     }
 16     inline void pd(int x){}
 17     inline void up(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
 18     void rotate(int x){
 19         int y=f[x],w=ch[y][1]==x;
 20         ch[y][w]=ch[x][w^1];
 21         if(ch[x][w^1])f[ch[x][w^1]]=y;
 22         if(f[y]){
 23             int z=f[y];
 24             if(ch[z][0]==y)ch[z][0]=x;
 25             if(ch[z][1]==y)ch[z][1]=x;
 26         }
 27         f[x]=f[y],ch[x][w^1]=y,f[y]=x,up(y);
 28     }
 29
 30     void splay(int x,int w){
 31         int s=1,i=x,y;q[1]=x;
 32         while(f[i])q[++s]=i=f[i];
 33         while(s)pd(q[s--]);
 34         while(f[x]!=w){
 35             y=f[x];
 36             if(f[y]!=w){if((ch[f[y]][0]==y)^(ch[y][0]==x))rotate(x);else rotate(y);}
 37             rotate(x);
 38         }
 39         if(!w)root=x;
 40         up(x);
 41     }
 42     void build(int &x,int l,int r,int fa=0)//按照数组下标建树
 43     {
 44         if(l>r)return;
 45         int mid=l+r>>1;
 46         nw(x,mid,fa);
 47         build(ch[x][0],l,mid-1,x);
 48         build(ch[x][1],mid+1,r,x);
 49         up(x);
 50     }
 51     inline int find(int _key) //返回值为key的节点 若无返回0 若有将其转移到根处
 52     {
 53         if(!root)return 0;
 54         int x=root;
 55         for(pd(x);x&&key[x]!=_key;)x=ch[x][key[x]<_key];
 56         if(x)splay(x,0);
 57         return x;
 58     }
 59     inline void Delete(int r)//删除下标为r的节点
 60     {
 61         splay(r,0);
 62         int pos=sz[ch[r][0]];
 63         splay(kth(pos),0);
 64         splay(kth(pos+2),root);
 65         ch[ch[root][1]][0]=0;
 66         up(ch[root][1]),up(root);
 67     }
 68     inline int kth(int k)//获得第k小
 69     {
 70         if(k>sz[root]||k<=0)return 0;
 71         int x=root,tmp;
 72         while(1)
 73         {
 74             pd(x),tmp=sz[ch[x][0]]+1;
 75             if(k==tmp)break;
 76             if(k<tmp)x=ch[x][0];else k-=tmp,x=ch[x][1];
 77         }
 78         return x;
 79     }
 80 }spt;
 81 //--------------------------------
 82
 83 int n,now,f[N],ed;
 84 struct node
 85 {
 86     int x,idx;
 87     bool operator <(const node &b)const{return x!=b.x?x<b.x:idx<b.idx;}
 88 }a[N];
 89 set<node>st;
 90 set<node>::iterator it;
 91 int find(int x){return f[x]!=x?f[x]=find(f[x]):x;}
 92
 93 int getkth(int x)
 94 {
 95     int rt=spt.find(x);
 96     return spt.sz[spt.ch[rt][0]]+1;
 97 }
 98
 99 int del()
100 {
101     it=st.lower_bound({a[ed].x,now});
102     if(it==st.end()||it->x > a[ed].x)
103     {
104         it=st.lower_bound({a[ed].x,1});
105     }
106     int tmp=it->idx;
107     st.erase(it);
108     return tmp;
109 }
110
111 int main()
112 {
113     scanf("%d",&n);
114     F(i,1,n)scanf("%d",&a[i].x),a[i].idx=i,f[i]=i,st.insert(a[i]);
115     sort(a+1,a+1+n);
116     spt.build(spt.root,1,n+2);
117     now=1,ed=1;
118     long long ans=0;
119     while(ed<=n)
120     {
121         int cur=getkth(now+1),tp=del();
122         int tmp=getkth(tp+1);
123         if(tmp>=cur)ans+=tmp-cur+1;
124         else ans+=spt.sz[spt.root]-cur+tmp-1;
125         int rt=spt.find(tp+1);
126         spt.Delete(rt);
127         if(tp<n)f[tp]=tp+1;
128         else f[tp]=1;
129         if(ed<n)now=find(f[tp]);
130         ed++;
131     }
132     printf("%lld\n",ans);
133     return 0;
134 }

时间: 2024-10-27 08:22:32

Codeforces Round #424 (Div. 2) E. Cards Sorting(线段树)的相关文章

Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery 题意: 给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大. 题解: 考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp, 考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a

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

链接: https://codeforces.com/contest/1263/problem/E 题意: The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which point

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并

D. Developing Game Pavel is going to make a game of his dream. However, he knows that he can't make it on his own so he founded a development company and hired n workers of staff. Now he wants to pick n workers from the staff who will be directly res

Codeforces Round #275 Div.1 B Interesting Array --线段树

题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的按位与和至少为多少. 更新时,如果val的pos位为1,那么整个区间的按位与和pos位也应该为1,否则与出来就不对了.(这是本题解题的核心) 那么此时更新 sum[rt] |= val 即可.然后再check一遍看是否满足所有条件即可. 代码: #include <iostream> #inclu

Codeforces Round #530 (Div. 2) E (树形dp+线段树)

链接: 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干需要花费bi时间,有两个玩家,玩家一可以移动到当前点的子节点也可以申请游戏结束返回根节点并吃沿途的饼干,玩家二可以删除当前点到儿子节点的一条边,走路和吃饼干都消耗时间,会给出一个总时间,在总时间内尽可能的多吃饼干,问最多能吃多少个? 思路: 由于是玩家一先手,那么最开始的最大边则不会被删除,但之后路途的最大边都会被玩家二删除,所以我们对于当前点我们需要求: 1.如果现在回头那么最多可以吃到多少饼干 2.向下

Codeforces Round #587 (Div. 3) F Wi-Fi(线段树+dp)

题意:给定一个字符串s 现在让你用最小的花费 覆盖所有区间 思路:dp[i]表示前i个全覆盖以后的花费 如果是0 我们只能直接加上当前位置的权值 否则 我们可以区间询问一下最小值 然后更新 #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const double eps = 1e-6; const int N = 2e5+7; typedef long long ll; const ll mod

Codeforces Round #424 (Div. 2) D 思维 E set应用,树状数组

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) D. Office Keys 题意:一条直线上,有个办公室坐标 p,有 n个人在a[i],有 k把钥匙在b[i],每个人必须拿到一把钥匙,然后到办公室.问怎么安排花的时间最短. tags:还是不懂套路啊..其实多画两下图就能够感觉出来,2333 关键是要看出来,n个人拿的 n把钥匙应该是连续的. 然后,就是瞎暴力.. #include<bits/stdc++.h> usi