codeforces 340D D. Bubble Sort Graph(dp+线段树)

题目链接:

codeforces 340D


题目大意:

给出一个程序,就是冒泡排序,每次如果发现相邻两个数前一个大于后一个,交换位置后建边,问最后得到的这个图中的最大独立集,这个最大独立集定义为所有的点都不相邻的最大点的集合的规模。


题目分析:

  • 首先我们可以知道对于a[i],它只会且一定会与后面的比它小的建边,所以我们只需要固定第一个点,然后找最长上升子序列即可。(这样能够保证没有相邻的点)
  • 定义状态dp[i]为以i项结尾的最长上升子序列的长度。
  • 转移方程如下:

    dp[i]=max{dp[j]+1},(1≤j≤i?1,a[j]<a[i])
  • 可以用线段树记录区间最大值,求取比a[i]小的最大的长度,最终优化后的复杂度是O(n?logn2)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007

using namespace std;

int n,a[MAX];

struct Tree
{
    int l,r,maxn;
}tree[MAX<<2];

void push_up ( int u )
{
    tree[u].maxn = max ( tree[u<<1].maxn , tree[u<<1|1].maxn );
}

void build ( int u , int l , int r )
{
    tree[u].l = l;
    tree[u].r = r;
    int mid = l+r>>1;
    tree[u].maxn = 0;
    if ( l == r ) return;
    build ( u<<1 , l , mid );
    build ( u<<1|1 , mid+1 , r );
}

void update ( int u , int x , int v )
{
    int l = tree[u].l;
    int r = tree[u].r;
    int mid = l+r>>1;
    if ( l == r )
    {
        tree[u].maxn = v;
        return;
    }
    if ( x > mid ) update ( u<<1|1 , x , v );
    else update ( u<<1 , x , v );
    push_up ( u );
}

int query ( int u , int left , int right )
{
    int l = tree[u].l;
    int r = tree[u].r;
    int mid = l+r>>1;
    if ( left <= l && r <= right )
        return tree[u].maxn;
    int ret = 0;
    if ( left <= mid && right >= l )
        ret = max ( ret , query ( u<<1 , left , right ) );
    if ( left <= r && right > mid )
        ret = max ( ret , query ( u<<1|1 , left , right ) );
    return ret;
}

int main ( )
{
    while ( ~scanf ( "%d" , &n ) )
    {
        for ( int i = 1 ; i <= n ; i++ )
            scanf ( "%d" , &a[i] );
        build ( 1 , 1, n );
        int x,ans=1;
        update ( 1 , a[1] , 1 );
        for ( int i = 2; i <= n ; i++ )
        {
            x = query ( 1 , 1 , a[i] );
            ans = max ( ans , x+1 );
            update ( 1 , a[i] , x+1 );
        }
        printf ( "%d\n" , ans );
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-18 16:40:21

codeforces 340D D. Bubble Sort Graph(dp+线段树)的相关文章

codeforces340D - Bubble Sort Graph dp + 最长上升子序列

题意:给你长为n的序列 ,每个节点都和在它前面且值比他大的点产生一条边,问你一个最大 两两点没有边的集合的 集合元素有多少 解题思路:想了半天才发现是最长上升子序列.. 解题代码: 1 // File Name: 340d.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月03日 星期日 12时31分24秒 4 5 #include<vector> 6 #include<list> 7 #include<map>

codeforces 340D Bubble Sort Graph(dp,LIS)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud  Bubble Sort Graph Iahub recently has learned Bubble Sort, an algorithm that is used to sort a permutation with n elements a1, a2, ..., an in ascending order. He is bored of this so simple al

Codeforces Beta Round #12 D. Ball (线段树)

题目大意: n个女性中,如果有一个女性的三维比这个女性的三维都大,这个女性就要自杀.问要自杀多少个. 思路分析: 先按照第一维排序. 然后离散化第二维,用第二维的下标建树,树上的值是第三维,更新的时候取最大值. 注意是按照第一维度从大到小进入线段树. 而且还要严格递增. 所以处理第一维度比较大小的时候要分开处理,要把相同的先判断,再更新入树. 那么如何判断这个女性是否自杀. 首先,你知道第一维度是从大到小的,所以先进树了的节点的第一维度一定更大. 再次,我们考虑第二维度,我们去树上第二维度下标大

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

[后缀数组+dp/AC自动机+dp+线段树] hdu 4117 GRE Words

题意: 给你N个字符串, N(1 <= N <= 2w), 所有串的长度加一起不超过30w.每个串有个值.这个值[-1000, 1000]. 问不打乱字符串顺序,从中取若干个字符串,使得前一个串是后一个串的子串,求满足前面调条件的字符串值得和最大,求这个值. 思路: 其实就是一个很明显的dp. dp[i]代表以第i个字符串结尾的最大权值. 但是就是子串这个问题怎么处理. 由于这题数据比较水可以用后缀数组处理这个问题. 将所有字符串拼接,做sa. 每次在height数组里往上和往下寻找公共前缀等

Codeforces 671D. Roads in Yusland(树形DP+线段树)

调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果我们枚举每条路去转移,会发现这条路沿线上的其他子树的答案难以统计,那怎么办呢,我们可以让这条路向上回溯的时候顺便记录一下,于是有$val[i]$表示必修i这条路,并且修完当前子树的最小代价. 则有转移$dp[x]=min(val[j])$,且$j$这条路必须覆盖$x$. $val[i]=(\sum

Codeforces 528B Clique Problem dp+线段树(or 树状数组)

题目链接:点击打开链接 题意: 给定数轴上的n个点. 下面n行每行两个数 xi, wi 表示点和点权. 对于任意两个点u, v 若dis(u,v) >= u_w+v_w 则这两个点间可以建一条边.(in other words 若两点间距离大于两点的权值和则可以建边) 找一个最大团,输出这个最大团的点数. 其实对于一个权值点我们可以认为是一个区间 如: 4 5 ,可以认为是区间[-1, 9] 则这个点可以从区间(-inf, 1]转移过来,即val(9) = max(val(9), 区间(-inf