Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2307 Accepted Submission(s): 344
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 the current apple is the first apple, or it is strictly higher than the previously picked one, then Taotao will pick this apple; otherwise, he will not pick.
Given the heights of these apples h1,h2,⋯,hn, you are required to answer some independent queries. Each query is two integers p,q, which asks the number of apples Taotao would pick, if the height of the p-th apple were q (instead of hp). Can you answer all these queries?
Input
The first line of input is a single line of integer T (1≤T≤10), the number of test cases.
Each test case begins with a line of two integers n,m (1≤n,m≤10^5), denoting the number of apples and the number of queries. It is then followed by a single line of n integers h1,h2,⋯,hn (1≤hi≤10^9), denoting the heights of the apples. The next m lines give the queries. Each of these m lines contains two integers p (1≤p≤n) and q (1≤q≤10^9), as described in the problem statement.
Output
For each query, display the answer in a single line.
Sample Input
1 5 3 1 2 3 4 4 1 5 5 5 2 3
Sample Output
1 5 3
For the first query, the heights of the apples were 5, 2, 3, 4, 4, so Taotao would only pick the first apple.
For the second query, the heights of the apples were 1, 2, 3, 4, 5, so Taotao would pick all these five apples.
For the third query, the heights of the apples were 1, 3, 3, 4, 4, so Taotao would pick the first, the second and the fourth apples.
题解:
上升序列问题,求单点修改之后的上升序列长度,即可将一段序列分为三部份。
如图,序列一储存的是该序列上升序列的长度与最大值,序列二是更改的值,序列三储存的是上升序列,如该图储存的是2、8、9,序列三需要动态维护,每次维护到被修改的值后一位,可用莫队算法对输入查询数据进行排序,动态更新序列三,答案即为序列一长度+序列二是否比序列一最大值大+序列三中有几个比序列一的最大值大的值
对于上图,如第七个数改为7,7比序列一的最大值6大,即用7在序列三中比较,序列三(2、8、9)中有两个数比7大,因此答案为3(序列一:1 4 6)+1(序列二:7)+2(序列三:8 9)=6。
序列三中的值是有序的,因此可用二分法查找。
代码如下:
#include
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int mmax = 1e5 + 5;
int ledate[mmax][2];//记录前缀的上升序列长度与最大值
int tmp[mmax]; //记录后缀的上升序列
int date[mmax], ans[mmax];
struct node
{
int p, q, index;
}op[mmax];
int cmp(node a, node b)
{
if (a.p == b.p)return a.q < b.q;
return a.p > b.p;
}
int upper(int l, int r, int x) //二分查找
{
while (lx)l = mid + 1;
else r = mid;
}
return l;
}
int main()
{
int T, n, m, le, ri, sum, j, up, k;
scanf("%d", &T);
while (T--)
{
up = le = ri = 0;
scanf("%d%d", &n, &m);
for (int i = 1;i <= n;i++)scanf("%d", &date[i]);
sum = 0;
ledate[0][0] = ledate[0][1] = 0;
for (int i = 1;i <= n;i++)
{
if (date[i] > le)
{
sum++;
le = date[i];
}
ledate[i][0] = sum;
ledate[i][1] = le;
}
memset(tmp, 0, sizeof(tmp));
for (int i = 1;i <= m;i++)
{
scanf("%d%d", &op[i].p, &op[i].q);
op[i].index = i;
}
sort(op + 1, op + 1 + m, cmp);
int num = 0, u = n, numtmp = 0;
for (int i = 1;i <= m;i++)
{
for (;u > op[i].p;u--)
{
while (num > 0 && tmp[num - 1] <= date[u])num--;
tmp[num++] = date[u];
}
//for (int kll = 0;kll < num;kll++)
// cout << tmp[kll] << " ";
//cout << endl;
if (op[i].p != op[i - 1].p)numtmp = num; //记录tmp中有多少值,if判断语句删去也没问题
ans[op[i].index] = ledate[op[i].p - 1][0];//ans先加上序列一上升序列的长度
if (op[i].q > ledate[op[i].p - 1][1]) //如果修改的值大于序列一的最大值,则序列长度加一
ans[op[i].index]++;
else op[i].q = ledate[op[i].p - 1][1]; //否则将被修改的值再修改为序列一的最大值
numtmp = upper(0, numtmp, op[i].q); //二分查找
ans[op[i].index] += numtmp;
}
for (int i = 1;i <= m;i++)
printf("%d\n", ans[i]);
}
}