zoukankan      html  css  js  c++  java
  • [NOIP2017]列队(线段树/裂点splay)

    考虑n=1的做法,就是支持:

    1.在线删一个数

    2.在结尾加一个数

    3.查询序列的第y个数

    用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可。

    对于满分同样如此,对每行开一个线段树,再对最后一列单独开一个。

    对于每次操作:

    若在最后一列:就是对最后一列直接使用n=1的做法。

    若不在:对第x列的前m-1个用n=1的做法,再将最后一列的第x个加入第x列的末尾,然后再对最后一列使用n=1的做法。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define lson ls[x],L,mid
     5 #define rson rs[x],mid+1,R
     6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     7 typedef long long ll;
     8 using namespace std;
     9 
    10 const int N=300010,M=N*40;
    11 ll ans;
    12 int n,m,Q,mx,x,y,nd,rt[N],sm[M],ls[M],rs[M];
    13 vector<ll>V[N];
    14 
    15 void ins(int &x,int L,int R,int pos){
    16     if (!x) x=++nd;
    17     if (L==R){ sm[x]++; return; }
    18     int mid=(L+R)>>1;
    19     if (pos<=mid) ins(lson,pos); else ins(rson,pos);
    20     sm[x]=sm[ls[x]]+sm[rs[x]];
    21 }
    22 
    23 int que(int x,int L,int R,int pos){
    24     if (L==R) return L;
    25     int mid=(L+R)>>1,t=mid-L+1-sm[ls[x]];
    26     if (t>=pos) return que(lson,pos); else return que(rson,pos-t);
    27 }
    28 
    29 int main(){
    30     scanf("%d%d%d",&n,&m,&Q); mx=max(n,m)+Q;
    31     rep(i,0,n) V[i].push_back(0);
    32     while (Q--){
    33         scanf("%d %d",&x,&y);
    34         if (y==m){
    35             int s=que(rt[0],1,mx,x);
    36             if (s<=n) ans=1ll*s*m; else ans=V[0][s-n];
    37             printf("%lld
    ",ans); ins(rt[0],1,mx,s); V[0].push_back(ans);
    38             continue;
    39         }
    40         int t=que(rt[x],1,mx,y);
    41         if (t<m) ans=1ll*(x-1)*m+t; else ans=V[x][t-(m-1)];
    42         printf("%lld
    ",ans); ins(rt[x],1,mx,t);
    43         int s=que(rt[0],1,mx,x); ll tmp=ans;
    44         if (s<=n) ans=1ll*s*m; else ans=V[0][s-n];
    45         V[x].push_back(ans); ins(rt[0],1,mx,s); V[0].push_back(tmp);
    46     }
    47     return 0;
    48 }

    或裂点splay,一个点代表一个区间,每次删除某个位置k就将其裂为[l,k-1],k,[k+1,r]三个部分,再删掉k。

    模板题。常数较大。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=2000010;
     8 int n,m,Q,nd,x,y,ch[N][2],rt[N],f[N];
     9 ll L[N],R[N],len[N];
    10 
    11 int get(ll l,ll r){ nd++; L[nd]=l; R[nd]=r; len[nd]=r-l+1; return nd; }
    12 void upd(int x){ len[x]=len[ch[x][0]]+len[ch[x][1]]+R[x]-L[x]+1; }
    13 
    14 void rot(int &rt,int x){
    15     int y=f[x],z=f[y],w=ch[y][1]==x;
    16     if (y==rt) rt=x; else ch[z][ch[z][1]==y]=x;
    17     f[x]=z; f[y]=x; f[ch[x][w^1]]=y;
    18     ch[y][w]=ch[x][w^1]; ch[x][w^1]=y; upd(y);
    19 }
    20 
    21 void splay(int &rt,int x){
    22     while (x!=rt){
    23         int y=f[x],z=f[y];
    24         if (y!=rt) ((ch[z][0]==y) ^ (ch[y][0]==x)) ? rot(rt,x) : rot(rt,y);
    25         rot(rt,x);
    26     }
    27     upd(x);
    28 }
    29 
    30 void ins(int &rt,ll k){
    31     int y=get(k,k);
    32     if (!rt) { rt=y; return; }
    33     int x=rt; while (ch[x][1]) x=ch[x][1];
    34     splay(rt,x); f[y]=x; ch[x][1]=y; upd(x);
    35 }
    36 
    37 int split(int &rt,int x,ll k){
    38     k+=L[x];
    39     int y=get(k,R[x]); R[x]=k-1;
    40     if (!ch[x][1]) f[y]=x,ch[x][1]=y;
    41     else{
    42         int s=ch[x][1];
    43         while (ch[s][0]) s=ch[s][0];
    44         f[y]=s; ch[s][0]=y;
    45     }
    46     splay(rt,y); return y;
    47 }
    48 
    49 int find(int x,ll &k){
    50     if (k<=len[ch[x][0]]) return find(ch[x][0],k);
    51     k-=len[ch[x][0]];
    52     if (k<=R[x]-L[x]+1) return x; else return k-=R[x]-L[x]+1,find(ch[x][1],k);
    53 }
    54 
    55 ll del(int &rt,ll k){
    56     int x=find(rt,k);
    57     if (k<R[x]-L[x]+1) split(rt,x,k);
    58     if (k>1) x=split(rt,x,k-1);
    59     splay(rt,x); f[ch[x][0]]=f[ch[x][1]]=0;
    60     if (!ch[x][0]) rt=ch[x][1];
    61     else{
    62         int y=ch[x][0]; rt=y;
    63         while (ch[y][1]) y=ch[y][1];
    64         splay(rt,y); ch[y][1]=ch[x][1];
    65         f[ch[x][1]]=y; upd(y);
    66     }
    67     return L[x];
    68 }
    69 
    70 int main(){
    71     freopen("phalanx.in","r",stdin);
    72     freopen("phalanx.out","w",stdout);
    73     scanf("%d%d%d",&n,&m,&Q);
    74     rep(i,1,n) rt[i]=++nd,L[i]=(i-1ll)*m+1,R[i]=1ll*i*m-1,len[i]=R[i]-L[i]+1;
    75     rep(i,1,n) ins(rt[0],1ll*i*m);
    76     while (Q--){
    77         scanf("%d%d",&x,&y); ll ans;
    78         ins(rt[x],del(rt[0],x));
    79         printf("%lld
    ",ans=del(rt[x],y));
    80         ins(rt[0],ans);
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    SAP MM模块教程(1)— 概述
    CodeSmith Generator
    EasyUI 左侧 tree 右侧 DataGrid模板
    C# 数据库访问公共类
    Easyui datagrid toolbar 模板
    EasyUI combogrid 更新查询参数 queryParams 重新加载
    Jenkins的搭建与使用
    Idea2020激活,全网最新教程(各版本通用),亲测2089!!!
    阿里云盘开启“个人云种子用户报名
    尚硅谷Java互联网大厂面试题第三季,1024干货
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9901958.html
Copyright © 2011-2022 走看看