• [loj3364]植物比较


    结论:设$b_{i}$满足该限制,则$a_{i}$合法当且仅当$forall i e j,a_{i} e a_{j}$且$forall |i-j|<k,[a_{i}<a_{j}]=[b_{i}<b_{j}]$,即$r_{i}$可以确定任意连续$k$位的相对大小关系

    充分性显然成立,必要性不会证QAQ

    构造$b_{i}$:考虑从0到$n-1$依次填写,每次填写的位置$x$需要满足:1.$r_{x}=k-1$;2.$forall i-k<j<i,r_{j} e k-1$

    第一个条件能够保证之后的$k-1$个数都比其小,第二个条件能保证之前的$k-1$个数都比其小(令$y$为前$k-1$个数中的最小值,再反证即可),因此这样是正确的

    对于第2个条件的判定,可以找出所有满足$r_{x}=k-1$的点组成一个set,在对这个set插入或删除的同时,找出所有满足第2个条件的点再组成一个set(因为还要删除)即可

    找到这样的位置后,填上当前的数,并令:1.$r_{x}=-infty$(保证自己不再被选);2.$forall i-k<j<i,r_{j}+=1$

    建图:对于每一个数$i$,设其前$k-1$个数中前驱后继为$pre$和$nex$,连有向边$(nex,i)$和$(i,pre)$,之后$a_{x}>a_{y}$当且仅当$x$能走到$y$

    虽然这张图并不一定是一条链,但不妨将所有边分为两类,向前(即$(nex,i)$)和向后(即$(i,pre)$)(并不是仅仅比较两数大小),那么如果存在路径,必然存在一条只走向前/向后的路径,使得能够到达$y$周围的$k$个位置,因此对两种路径分别倍增维护即可

      1 #include "plants.h"
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 #define N 200005
      5 #define oo 0x3f3f3f3f
      6 #define L (k<<1)
      7 #define R (L+1)
      8 #define mid (l+r>>1)
      9 set<int>se;
     10 set<int>::iterator itt;
     11 set<pair<int,int> >s;
     12 set<pair<int,int> >::iterator it;
     13 int n,k,a[N],r[N],tag[N<<2],f[N<<2],fa[2][N][21],d[2][N][21];
     14 void upd(int k,int x){
     15     tag[k]+=x;
     16     f[k]+=x;
     17 }
     18 void down(int k){
     19     upd(L,tag[k]);
     20     upd(R,tag[k]);
     21     tag[k]=0;
     22 }
     23 void update(int k,int l,int r,int x,int y,int z){
     24     if ((l>y)||(x>r))return;
     25     if ((x<=l)&&(r<=y)){
     26         upd(k,z);
     27         return;
     28     }
     29     down(k);
     30     update(L,l,mid,x,y,z);
     31     update(R,mid+1,r,x,y,z);
     32     f[k]=max(f[L],f[R]);
     33 }
     34 int query(int k,int l,int r){
     35     if (l==r)return l;
     36     down(k);
     37     if (f[L]==f[k])return query(L,l,mid);
     38     return query(R,mid+1,r);
     39 }
     40 bool pd(int x){
     41     if (x>=k-1)return (*se.upper_bound(x-k))==x;
     42     return (x==(*se.begin()))&&(se.upper_bound(x-k+n)==se.end());
     43 }
     44 void add(int x){
     45     itt=se.upper_bound(x);
     46     if (itt==se.end())itt=se.begin();
     47     int y=(*itt);
     48     if (pd(y))s.erase(make_pair(y,0));
     49     se.insert(x);
     50     if (pd(x))s.insert(make_pair(x,0));
     51     if (pd(y))s.insert(make_pair(y,0));
     52 }
     53 void del(int x){
     54     se.erase(x);
     55     itt=se.upper_bound(x);
     56     if (itt==se.end())itt=se.begin();
     57     if (pd(*itt))s.insert(make_pair((*itt),0));
     58 }
     59 int dis(int x,int y){
     60     if (x<=y)return y-x;
     61     return y+n-x;
     62 }
     63 void init(int kk,vector<int>rr){
     64     n=rr.size();
     65     k=kk;
     66     for(int i=0;i<n;i++)r[i]=rr[i];
     67     for(int i=0;i<n;i++)update(1,0,n-1,i,i,r[i]);
     68     for(int i=0;i<n;i++){
     69         while (f[1]==k-1){
     70             int x=query(1,0,n-1);
     71             add(x);
     72             update(1,0,n-1,x,x,-oo);
     73         }
     74         int x=(*s.begin()).first;
     75         s.erase(s.begin());
     76         del(x);
     77         a[x]=i;
     78         if (x-k+1>=0)update(1,0,n-1,x-k+1,x-1,1);
     79         else{
     80             update(1,0,n-1,0,x-1,1);
     81             update(1,0,n-1,x-k+1+n,n-1,1);
     82         }
     83     }
     84     for(int i=0;i<k;i++)s.insert(make_pair(a[i],i));
     85     for(int i=0;i<n;i++){
     86         s.erase(make_pair(a[i],i));
     87         it=upper_bound(s.begin(),s.end(),make_pair(a[i],i));
     88         if (it==s.end())fa[0][i][0]=i;
     89         else fa[0][i][0]=(*it).second;
     90         d[0][i][0]=dis(i,fa[0][i][0]);
     91         it=upper_bound(s.begin(),s.end(),make_pair(a[(i+k)%n],(i+k)%n));
     92         if (it==s.end())fa[1][(i+k)%n][0]=(i+k)%n;
     93         else fa[1][(i+k)%n][0]=(*it).second;
     94         d[1][(i+k)%n][0]=dis(fa[1][(i+k)%n][0],(i+k)%n);
     95         s.insert(make_pair(a[(i+k)%n],(i+k)%n));
     96     }
     97     for(int p=0;p<2;p++)
     98         for(int i=1;i<=20;i++)
     99             for(int j=0;j<n;j++){
    100                 fa[p][j][i]=fa[p][fa[p][j][i-1]][i-1];
    101                 d[p][j][i]=min(d[p][j][i-1]+d[p][fa[p][j][i-1]][i-1],n);
    102             }
    103 }
    104 bool pd(int x,int y){
    105     int dd=dis(x,y),z=x;
    106     for(int i=20;i>=0;i--)
    107         if (d[0][x][i]<=dd){
    108             dd-=d[0][x][i];
    109             x=fa[0][x][i];
    110         }
    111     if ((dd<k)&&(a[x]<=a[y]))return 1;
    112     dd=dis(y,x=z);
    113     for(int i=20;i>=0;i--)
    114         if (d[1][x][i]<=dd){
    115             dd-=d[1][x][i];
    116             x=fa[1][x][i];
    117         }
    118     return ((dd<k)&&(a[x]<=a[y]));
    119 }
    120 int compare_plants(int x,int y){
    121     if ((a[x]<a[y])&&(pd(x,y)))return -1;
    122     if ((a[x]>a[y])&&(pd(y,x)))return 1;
    123     return 0;
    124 }
    View Code
  • 相关阅读:
    小程序自定义组件(3)子向父传参
    postgresql插件安装
    二进制减法的实现
    mysql锁表问题
    mysql查看修改参数
    众数问题-找出超过一半的数
    只出现一次的数
    元素最大间距离
    第一个缺失数字
    局部最小值位置
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13812734.html
Copyright © 2020-2023  润新知