JZOJ 5610. 【NOI2018模拟3.29】第1题

题目

这里写图片描述

题解

考虑链。
对于链,直接做一遍最长不下降子序列。
考虑菊花。同一个节点的不同的子树是不会互相影响的。
考虑如何构造最长不下降子序列。
f[i] f [ i ] 表示长度为 i i 的不下降子序列的末尾的最小值。新加入一个元素,二分就好了。
思维变换:每个点x维护一个set,表示 x x 的子树要留下来的点的权值,假设x作为数组的最后一个元素,即将加入 f f ,那么是不是替换其中一个元素或者是将ax加入set?

心得

把f看做什么?

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define N 200010
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
    int to,next;
};note edge[N*2];
int tot,head[N];
int i,j,k,l,n,m,ans,wz;
int x,y;
int val[N],fa[N];
multiset<int>s[N];
multiset<int>::iterator u;
bool p;
int read(){
    int rs=0,fh=1;char ch;
    while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
    if(ch=='-')fh=-1,ch=getchar();
    while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
    return fh*rs;
}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
void merge(int x,int y){
    if(s[x].size()>s[y].size())swap(s[x],s[y]);
    for(u=s[x].begin();u!=s[x].end();u++)s[y].insert(*u);
    s[x].clear();
}
void dg(int x){
    int i;
    for(i=head[x];i;i=edge[i].next){
        if(fa[x]==edge[i].to)continue;
        fa[edge[i].to]=x;
        dg(edge[i].to);
        merge(edge[i].to,x);
    }
    u=s[x].upper_bound(val[x]);
    if(u!=s[x].end())s[x].erase(u);
    s[x].insert(val[x]);
}
int main(){
    freopen("simple.in","r",stdin);
    freopen("simple.out","w",stdout);
    n=read();
    fo(i,1,n)val[i]=-read();
    fo(i,1,n-1){
        x=read();y=read();
        lb(x,y);lb(y,x);
    }
    dg(1);
    printf("%d",n-s[1].size());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值