Codeforces 1132 G Greedy Subsequences —— 构造树

This way

题意:

给你一些数,定义greedy subsequence:在目标数组为数组c的前提下,构造一个序列p1,p2…pl使得1<=p1,p1<p2,p2<p3…
并且pl<=c的长度,且每个p值要最小,也就是说1 5 2 3 4这个数组,在p1等于1的情况下,p2一定等于2
greedy subsequence就是l的最大值。
现在给你数组a,和一个值k,每次你要做greedy subsequence的区间为i-i+k-1,(1<=i<=n-k+1)
问你每次greedy subsequence的值是多少

题解:

有史以来最快AC的2600,只用了半个小时左右。。
你画一张图就会发现,这个贪心的上升子序列是一棵树,准确的说是一个森林。然后还有最重要的一点,从后往前看,每个点的子树是一个连续的区间。
假设第i个数是x,如果i-1是x-1,那么i-1是x的子树,如果i-1是x+1,那么再往前的数,一定不会连到i,也就是i的子树结束了。
我们首先用树状数组处理出每个点的右边连到哪里,再for一遍处理出每个点的最左端的位置。dfs求出每个点的深度。
那么我们从后往前做,对于每左移一格,右端点的子树的区间-1.用线段树维护区间深度最大值即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct node
{
    int to,next;
}e[N];
int cnt,head[N];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
struct Array_Tree
{
    int mi[N];
    int lowbit(int x){return x&(-x);}
    void add(int x,int v)
    {
        for(int i=x;i;i-=lowbit(i))
            mi[i]=min(mi[i],v);
    }
    int query(int x)
    {
        int ans=N;
        for(int i=x;i<N;i+=lowbit(i))
            ans=min(ans,mi[i]);
        return ans;
    }
}t1;
struct Line_Tree
{
    int mx[N*4],flag[N*4],dep[N];
    void dfs(int x,int fa)
    {
        dep[x]=dep[fa]+1;
        for(int i=head[x];~i;i=e[i].next)
        {
            int ne=e[i].to;
            dfs(ne,x);
        }
    }
    void push_down(int root)
    {
        if(!flag[root])return ;
        mx[root<<1]+=flag[root];
        mx[root<<1|1]+=flag[root];
        flag[root<<1]+=flag[root];
        flag[root<<1|1]+=flag[root];
        flag[root]=0;
    }
    void build(int l,int r,int root)
    {
        if(l==r)
        {
            mx[root]=dep[l];
            return ;
        }
        int mid=l+r>>1;
        build(l,mid,root<<1);
        build(mid+1,r,root<<1|1);
        mx[root]=max(mx[root<<1],mx[root<<1|1]);
    }
    void update(int l,int r,int root,int ql,int qr,int v)
    {
        if(l>=ql&&r<=qr)
        {
            mx[root]+=v;
            flag[root]+=v;
            return ;
        }
        push_down(root);
        int mid=l+r>>1;
        if(mid>=ql)
            update(l,mid,root<<1,ql,qr,v);
        if(mid<qr)
            update(mid+1,r,root<<1|1,ql,qr,v);
        mx[root]=max(mx[root<<1],mx[root<<1|1]);
    }
    int query(int l,int r,int root,int ql,int qr)
    {
        if(l>=ql&&r<=qr)
            return mx[root];
        push_down(root);
        int mid=l+r>>1,ans=0;
        if(mid>=ql)
            ans=query(l,mid,root<<1,ql,qr);
        if(mid<qr)
            ans=max(ans,query(mid+1,r,root<<1|1,ql,qr));
        return ans;
    }
}t2;
int a[N],le[N],ans[N],pre[N];
vector<int>vec;
int main()
{
    memset(head,-1,sizeof(head));
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<N;i++)t1.mi[i]=N,le[i]=i;
    for(int i=n;i>=1;i--)
    {
        int p=t1.query(a[i]+1);
        if(p==N)
            vec.push_back(i);
        else
            add(p,i),le[p]=i,pre[i]=p;
        t1.add(a[i],i);
    }
    for(int i=1;i<=n;i++)le[pre[i]]=min(le[pre[i]],le[i]);
    for(auto i:vec)t2.dfs(i,0);
    t2.build(1,n,1);
    for(int i=n-k+1;i>=1;i--)
    {
        ans[i]=t2.query(1,n,1,i,i+k-1);
        t2.update(1,n,1,le[i+k-1],i+k-1,-1);
    }
    for(int i=1;i<=n-k+1;i++)
        printf("%d%c",ans[i]," \n"[i==n-k+1]);
    return 0;
}

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/101473529