HDU暑假多校第八场J-Taotao Picks Apples

一、题意

给定一个序列,之后给出若干个修改,修改的内容为在原序列的基础上,将某一位元素的值改成给定的值<每次修改相互独立,不保存修改后的结果>。之后询问,在选择第一位元素的情况下,最长递增子序列的长度是多少。

二、题解

考虑不经修改的情况,应当设dp[i]为选取当前位情况下的最长递增子串的长度。则对于这道题,应当认为对于修改a为b,设l_pos为a左边最大的元素的位置,r_pos为a右边大于max(b,r_pos)的元素的位置。则有ans = dp[1] - dp[l_pos] + 1 + dp[r_pos];对于b本身大于位于l_pos的元素,应当给结果+1。

#include<bits/stdc++.h>
using namespace std;

#define ll long long 

const int MAXN = 1000233;

class Node{
    public:
        int l,r,lc,rc,maxx;
};
Node nodes[MAXN];
int nodes_num;
int t,n,m;

int arr[MAXN];
int dp[MAXN];

void tree_init(int a,int b){
    int now = nodes_num++;
    nodes[now].l = a;
    nodes[now].r = b;
    if(a == b-1){
        nodes[now].maxx = arr[a];
        return ;
    }
    int mid = (a+b)/2;
    nodes[now].lc = nodes_num;
    tree_init(a,mid);
    nodes[now].rc = nodes_num;
    tree_init(mid,b);
    nodes[now].maxx = max(nodes[nodes[now].lc].maxx,nodes[nodes[now].rc].maxx);
}

int find_max(int now){
    int l = nodes[now].l;
    int r = nodes[now].r;
    if(l == r-1)return l;
    int maxx = nodes[now].maxx;
    int lc = nodes[now].lc;
    int rc = nodes[now].rc;
    if(maxx == nodes[lc].maxx)return find_max(lc);
    else return find_max(rc);
}

int find_biggest(int now,int a,int b){
    int l = nodes[now].l;
    int r  =nodes[now].r;
    if(l == a&&r == b){
        return find_max(now);
    }
    int mid = (l+r)/2;
    int ret ;
    int lc = nodes[now].lc;
    int rc = nodes[now].rc;
    if(a<mid){
        ret = find_biggest(lc,a,min(b,mid));
        if(b>mid){
            int tmp = find_biggest(rc,mid,b);
            ret = arr[ret] >= arr[tmp] ? ret:tmp;
        }
    }else ret = find_biggest(rc,a,b);
    return ret;
}

int find_left(int now,int key){
    int l = nodes[now].l;
    int r = nodes[now].r;
    if(l == r-1)return l;
    int lc = nodes[now].lc;
    int rc = nodes[now].rc;
    if(nodes[lc].maxx > key)return find_left(lc,key);
    else return find_left(rc,key);
}

int find_first(int now,int pos, int key){
    int l = nodes[now].l;
    int r = nodes[now].r;
    if(l >= pos){
        return find_left(now,key);
    }
    int mid = (l+r)/2;

    int lc = nodes[now].lc;
    int rc = nodes[now].rc;
    int ret ;
    if(pos < mid && nodes[lc].maxx > key){
        ret = find_first(lc,pos,key);
        if(ret >= pos && arr[ret] > key)return ret;
    }
    if(nodes[rc].maxx <= key)return r-1;
    return find_first(rc,pos,key);

}

void init(){
    scanf("%d %d",&n,&m);
    nodes_num = 0;
    arr[0] = -100233;
    arr[n+1] = INT_MAX;
    for(int i=1;i<=n;++i)scanf("%d",&arr[i]);
    tree_init(0,n+2);
    memset(dp,0,sizeof(dp));
    for(int i=n;i>=1;--i){
        dp[i] = dp[find_first(0,i+1,arr[i])]+1;
    }
    dp[0] = dp[1]+1;
    for(int i=0;i<m;++i){
        int a,b;
        scanf("%d %d",&a,&b);
        int l_pos = find_biggest(0,0,a);
        int key = max(b,arr[l_pos]);
        int r_pos = find_first(0,a+1,max(b,arr[l_pos]));
        int ans = dp[1] - dp[l_pos] + 1 + dp[r_pos];
        if(b > arr[l_pos] )ans++;
        cout<<ans<<‘\n‘;
    }

}

int main(){

    cin>>t;
    while(t--)init();

    return 0;
}

原文地址:https://www.cnblogs.com/rikka/p/9487455.html

时间: 2024-10-11 05:22:46

HDU暑假多校第八场J-Taotao Picks Apples的相关文章

2014 HDU多校弟八场H题 【找规律把】

看了解题报告,发现看不懂 QAQ 比较简单的解释是这样的: 可以先暴力下达标,然后会发现当前数 和 上一个数 的差值是一个 固定值, 而且等于当前数与i(第i个数)的商, 于是没有规律的部分暴力解决,有规律的套公式 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <cstring&g

2014 HDU多校弟五场J题 【矩阵乘积】

题意很简单,就是两个大矩阵相乘,然后求乘积. 用 Strassen算法 的话,当N的规模达到100左右就会StackOverFlow了 况且输入的数据范围可达到800,如果变量还不用全局变量的话连内存开辟都开不出来 1 #pragma comment(linker, "/STACK:16777216") 2 #include <iostream> 3 #include <stdio.h> 4 #define ll long long 5 using namesp

2014 HDU多校弟六场J题 【模拟斗地主】

这是一道5Y的题目 有坑的地方我已在代码中注释好了 QAQ Ps:模拟题还是练的太少了,速度不够快诶 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <climits> #include <cstring> #include <cmath> #inclu

多校第八场:图论出度

HDU 4948 这题比赛的时候遗憾了,我看了这道题,然后觉得挺简单的. 刚开始一看题上,想到的就是拓扑排序,然后脑子想啊想--感觉就是拓扑排序的逆序,然后发现挺水的-- 因为说了要想发展某个城市的话,就必须有另一个城市作为它发展的前提,即城市u->w这样连边,表示要想发展城市w,前提是u已经是发展过的城市了.那这样的话不是很简单嘛. 即统计出出度最多的就是第一个要发展的城市了,因为u->w这样连边可以看出算出出度最多的依次从大到小排序就行了. 哎呀,不过可惜了,因为看见没人交这题,然后也不敢

hdu-4893-Wow! Such Sequence!-线段树【2014多校第三场-J】

题意:一个初始为0的数组,支持三种操作:1.向第k个数添加d,(|d| < 2^31);2.把[l, r]区间内的数字都换成与它最相近的Fibonacci数;3.询问[l, r]区间的和. 思路:初始化Fibonacci数组,longlong 类型内90个就够用了. 线段树区间查询,用lazy标记, sgt[]记录线段树各个节点的区间和, fib_num_sum[]记录与各个叶子节点当前值最接近的Fibonacci数,传递到区间fib_num_sum[]就是区间Fibonacci数的和. 操作1

hdu6406 Taotao Picks Apples 多校第8场1010

Problem Description There is an apple tree in front of Taotao's house. When autumn comes, n apples on the tree ripen, and Taotao will go to pick these apples. When Taotao picks apples, Taotao scans these apples from the first one to the last one. If

HDU 4870 Rating (2014 多校联合第一场 J)(概率)

题意: 一个人有两个TC的账号,一开始两个账号rating都是0,然后每次它会选择里面rating较小的一个账号去打比赛,每次比赛有p的概率+1分,有1-p的概率-2分,当然如果本身是<=2分的也就还是回到0分.然后问最后其中一个账号到达20分时需要打多少次比赛. 思路: 因为每次50分,到达1000分,所以可以看做每次1分,到达20分dp[i]表示i到20的数学期望那么dp[i] = dp[i+1]*p+dp[i-2]*q+1;令t[i] = dp[i+1]-dp[i]则t[i] = (t[i

HDU 5358 多校第6场 First One

First One Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 672    Accepted Submission(s): 193 Problem Description soda has an integer array . Let  be the sum of . Now soda wants to know the va

2016多校第八场 hdu5821 Ball

http://acm.hdu.edu.cn/showproblem.php?pid=5821 水题的精华..... 有n个球,给出目前的颜色序列a和目标颜色序列b,再给出m个可以重新安排球顺序的球区间,这m个区间是不得重新安排区间顺序,问能否达到目标的颜色序列 这题是那道给出一个字典,再给出某一个字符串S,S只要能经过重排得到字典中任意一个字符串T就输出yes的进化版. 这里是for b[i] a[i]==b[i],所以可以通过映射关系重新编号b为1-n,再重新编号a为1~n使得关系变成for