BZOJ5249: [2018多省省队联测]IIIDX

$n leq 500000$个数字,给实数$k$,问用这些数字填上的,满足$d_i geq d_{left lfloor frac{i}{k} ight floor}$的字典序最大的序列。

如果数字不同的话按后序遍历从大到小填就行了。

如果数字相同的话就不行。比如输入4 2 1 1 1 2。

预定。每选一个数,要预定几个比他大的数。首先从小到大排序。

方法零:线段树上维护每个数选了没选。在同一层的时候,每选一个数,就预定他左边紧贴着他的,他子树大小个数的数字。然后这层选完再把它还原回去。用个可持久化可以还原回去。难写。

方法一:线段树上维护每个数右边有几个数还没预定。每次找数需要找一个x,满足x左边的“未预定数”都大于等于x的子树大小,找权值尽量大的、同权值尽量靠左的数字选中。选完后,把它左边所有数的“未预定数”减去他的子树大小。决定一个点时取消它父亲的影响,注意只用取消一次。

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 //#include<time.h>
  5 //#include<complex>
  6 //#include<queue>
  7 #include<algorithm>
  8 #include<stdlib.h>
  9 using namespace std;
 10 
 11 #define LL long long
 12 int qread()
 13 {
 14     char c; int s=0; while ((c=getchar())<'0' || c>'9');
 15     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s;
 16 }
 17 
 18 //Pay attention to '-' , LL and double of qread!!!!
 19 
 20 int n; double K;
 21 #define maxn 500011
 22 int num[maxn];
 23 struct Edge{int to,next;}edge[maxn]; int first[maxn],le=2;
 24 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
 25 
 26 int size[maxn];
 27 void dfs(int x)
 28 {
 29     size[x]=1;
 30     for (int i=first[x];i;i=edge[i].next)
 31     {
 32         Edge &e=edge[i];
 33         dfs(e.to); size[x]+=size[e.to];
 34     }
 35 }
 36 
 37 struct SMT
 38 {
 39     struct Node{int ls,rs; int Min,add;}a[maxn<<1];
 40     int size,n;
 41     void up(int x) {a[x].Min=min(a[a[x].ls].Min,a[a[x].rs].Min);}
 42     void build(int &x,int L,int R)
 43     {
 44         x=++size;
 45         if (L==R) {a[x].Min=n-L; return;}
 46         int mid=(L+R)>>1;
 47         build(a[x].ls,L,mid); build(a[x].rs,mid+1,R);
 48         up(x);
 49     }
 50     void build(int m) {n=m; size=0; int x; build(x,1,n);}
 51     
 52     void addsingle(int x,int v) {a[x].add+=v; a[x].Min+=v;}
 53     void down(int x) {if (a[x].add) {addsingle(a[x].ls,a[x].add); addsingle(a[x].rs,a[x].add); a[x].add=0;}}
 54     
 55     int ql,qr,v;
 56     void Add(int x,int L,int R)
 57     {
 58         if (ql<=L && R<=qr) {addsingle(x,v); return;}
 59         down(x);
 60         int mid=(L+R)>>1;
 61         if (ql<=mid) Add(a[x].ls,L,mid);
 62         if (qr>mid) Add(a[x].rs,mid+1,R);
 63         up(x);
 64     }
 65     void add(int L,int R,int v) {if (L>R) return; ql=L; qr=R; this->v=v; Add(1,1,n);}
 66     
 67     int Query(int x,int L,int R)
 68     {
 69         if (L==R) return L;
 70         down(x);
 71         int mid=(L+R)>>1;
 72         if (a[a[x].ls].Min>=v) return Query(a[x].rs,mid+1,R);
 73         return Query(a[x].ls,L,mid);
 74     }
 75     int query(int val) {v=val; return Query(1,1,n);}
 76     
 77     int Find(int x,int L,int R)
 78     {
 79         if (L==R) return L;
 80         down(x);
 81         int mid=(L+R)>>1;
 82         if (num[mid]>=v) return Find(a[x].ls,L,mid);
 83         return Find(a[x].rs,mid+1,R);
 84     }
 85     int find(int val) {v=val; return Find(1,1,n);}
 86     
 87 }t;
 88 
 89 int ans[maxn],fa[maxn];
 90 int main()
 91 {
 92     n=qread(); scanf("%lf",&K);
 93     for (int i=1;i<=n;i++) num[i]=qread();
 94     
 95     fa[0]=-1;
 96     for (int i=1;i<=n;i++) in(fa[i]=(int)(i/K+1e-9),i);
 97     dfs(0);
 98     
 99     sort(num+1,num+1+n); num[++n]=0x3f3f3f3f;
100     t.build(n);
101     for (int i=1;i<n;i++)
102     {
103         if (fa[i] && fa[i]!=fa[i-1]) t.add(1,ans[fa[i]],size[fa[i]]-1);
104         int val=num[t.query(size[i])-1]; int p=t.find(val);
105         ans[i]=p; t.add(1,ans[i],-size[i]);
106     }
107     
108     for (int i=1;i<n;i++) printf("%d ",num[ans[i]]);
109     return 0;
110 }
View Code

方法二:看不太懂

原文地址:https://www.cnblogs.com/Blue233333/p/8880806.html