B3666 求数列所有后缀最大值的位置 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意:
题目的要求是(ai > aj ,i < j < |a| ),也就是说从后往前看(从后往前遍历),这个元素是当前数列的最大值的话,就将下标异或,每输入一个x,就输出一个结果
题解:
如果每一次都要从后往前遍历会特别浪费时间,不妨找一下规律,会发现只有形成单调递减的数列,才会异或所有下标,由此我们能想到单调栈,中间那些不能形成单调递减的元素,已经没有用处了,我们就可以把他pop掉。
整理以上思路,该题就是要,每加入一次x,就异或一次(因为x是最后一个,一定是后缀最大值元素),然后构建一个单调栈(存下标的),如果有元素大于栈顶下标的元素,将弹出的下标再异或一次(利用两个相同的数异或等于0的性质,我们可以把该下标处理掉),接着输出每一步的异或和。
同时还要注意,该题的ai的范围是0~2^64,大于long long范围,而且我们知道异或不会异或出负数,所以需要用到unsigned long long
代码如下:
#include<bits/stdc++.h>
#define int unsigned long long
#define endl '\n'
using namespace std;
int a[1000010];
void sl()
{
stack<int> st;
int n , ans = 0, last = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
while(!st.empty() && a[i] > a[st.top()]) // 构建单调栈,有不单调的就pop
{
last ^= st.top(); // 处理掉没有用的下标
st.pop();
}
last ^= i;
ans = last; // last即为答案
st.push(i);
cout << ans << endl;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
T = 1;
while(T--) sl();
return 0;
}