• 解题:洛谷1975 排队


    题面

    考虑交换两个数的影响,发现只有夹在两个数中间的大于/小于两个数的数会产生影响,而两边的状态是不变的,然后就变成了序列分块的经典问题

    注意细节.jpg

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 const int N=20005,Sq=150;
     8 int a[N],uni[N],blo[N],tra[N],pts[Sq][2];
     9 int n,m,t1,t2,sqr,cnt,len,ans;
    10 vector<int> v[Sq];
    11 int prework()
    12 {
    13     sqr=sqrt(n)+10,pts[cnt=1][0]=1;
    14     sort(uni+1,uni+1+n),len=unique(uni+1,uni+1+n)-uni-1;
    15     for(int i=1;i<=n;i++)
    16     {
    17         a[i]=lower_bound(uni+1,uni+1+len,a[i])-uni;
    18         blo[i]=(i-1)/sqr+1,v[blo[i]].push_back(a[i]);
    19         if(i%sqr==0) pts[cnt++][1]=i,pts[cnt][0]=i+1;
    20     }
    21     pts[cnt][1]=n;
    22     for(int i=1;i<=cnt;i++)    
    23         sort(v[i].begin(),v[i].end());
    24     int ret=0;
    25     for(int i=1;i<=n;i++)
    26     {
    27         int tmp=len-a[i]+1,tep=tmp-1;
    28         while(tep) ret+=tra[tep],tep-=tep&-tep;
    29         while(tmp<=n) tra[tmp]++,tmp+=tmp&-tmp;
    30     }
    31     return ret;
    32 }
    33 int query(int x,int t)
    34 {
    35     int ret=0;
    36     if(!t)
    37     {
    38         if(blo[t1]!=blo[t2])
    39         {
    40             for(int i=t1;i<=pts[blo[t1]][1];i++) ret+=(a[i]<x);
    41             for(int i=pts[blo[t2]][0];i<=t2;i++) ret+=(a[i]<x); 
    42             for(int i=blo[t1]+1;i<=blo[t2]-1;i++) 
    43                 ret+=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin();
    44          }
    45         else 
    46             for(int i=t1;i<=t2;i++) ret+=(a[i]<x);
    47     }
    48     else
    49     {
    50         if(blo[t1]!=blo[t2])
    51         {
    52             for(int i=t1;i<=pts[blo[t1]][1];i++) ret+=(a[i]>x);
    53             for(int i=pts[blo[t2]][0];i<=t2;i++) ret+=(a[i]>x); 
    54             for(int i=blo[t1]+1;i<=blo[t2]-1;i++) 
    55                 ret+=v[i].size()-(upper_bound(v[i].begin(),v[i].end(),x)-v[i].begin());
    56          }
    57         else 
    58             for(int i=t1;i<=t2;i++) ret+=(a[i]>x);
    59     }
    60     return ret;
    61 }
    62 void rebuild(int x,int y)
    63 {
    64     swap(a[x],a[y]); 
    65     int b1=blo[x],b2=blo[y]; if(b1==b2) return ; 
    66     v[b1].clear(),v[b2].clear(); 
    67     for(int i=pts[b1][0];i<=pts[b1][1];i++)
    68         v[b1].push_back(a[i]);
    69     for(int i=pts[b2][0];i<=pts[b2][1];i++)
    70         v[b2].push_back(a[i]);
    71     sort(v[b1].begin(),v[b1].end());
    72     sort(v[b2].begin(),v[b2].end());
    73 }
    74 int main()
    75 {
    76     scanf("%d",&n);
    77     for(int i=1;i<=n;i++)
    78         scanf("%d",&a[i]),uni[i]=a[i];
    79     printf("%d
    ",ans=prework());
    80     scanf("%d",&m);
    81     while(m--)
    82     {
    83         scanf("%d%d",&t1,&t2);
    84         if(t1>t2) swap(t1,t2);
    85         int a1=a[t1],a2=a[t2];
    86         if(t1!=t2-1)
    87         {
    88             t1++,t2--;
    89             ans+=query(a1,1)-query(a1,0);
    90             ans+=query(a2,0)-query(a2,1);
    91             t1--,t2++;
    92         }
    93         if(a1<a2) ans++; if(a1>a2) ans--; 
    94         rebuild(t1,t2); printf("%d
    ",ans);
    95     }
    96     return 0;
    97 }
    View Code
  • 相关阅读:
    uniapp 常用的基础知识
    uniapp接口请求(第一种)
    系统对象的使用——Cookie,ViewState,Session,Application
    网页跳转
    存储过程的使用——游标
    存储过程的使用——循环,条件语句
    存储过程的使用——定义变量
    页面读取英语单词
    加密
    XMind: ZEN 快捷键
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9960390.html
Copyright © 2020-2023  润新知