題目鏈接
題目大意
T組數據。
每組給一個長度爲 的數組, 初始全爲0, 有 次操作, 每次操作將區間 中 的更新成v。
最後詢問
輸入的數據由題目給的方式生成。
數據範圍
解題思路
比賽的時候這道題是沒寫出來的, 看到了數據範圍肯定是卡線段樹, 線段樹需要的複雜度是 再加上T組。 顯然TLE, 最後也沒有想到正解。
賽後看了一下題解, 豁然開朗, 居然可以這麼做, 複雜度一下就降到了 。
對於每一段區間 , 可以將其轉換爲兩段二的冪次的長度。
令 , 則 可拆成 和 , 兩個區間, 保證了完全覆蓋。 (就是RMQ的思想)。
這樣一共最多有 種線段,從長度從大到小枚舉, 每一個線段可以轉換爲等分的兩部分的線段, 對於完全相同的線段, 維護最大值即可。 這樣一直做到長度爲1的線段就結束了。
用數組存一下, 那麼 表示從 開始 這麼長的線段的攜帶的最大值。
每次則可以轉移爲
最後按照題目要求計算答案即可。
還有就是題目給的生成數據的方式有點坑, 非常慢.
其實可以不用求出 數組, 每次計算三個值就可以了。 不需要存起來。 同時也可以減少模 的次數。
AC代碼
/********************************************
*Author* :ZZZZone
*Created Time* : 一 8/ 6 20:26:08 2018
* Ended Time* : 一 8/ 6 20:52:16 2018
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
inline void OPEN(string s){
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
const int MAXN = 1e5;
const int MAXV = 5e6;
const int INF = 1 << 30;
unsigned X, Y, Z;
int n,m;
int Log2[MAXN+5];
int pow2[30];
LL Line[MAXN+5][35];
unsigned getnum(){
X = X ^ (X << 11);
X = X ^ (X >> 4);
X = X ^ (X << 5);
X = X ^ (X >> 14);
unsigned W = X ^ (Y ^ Z);
X = Y;
Y = Z;
Z = W;
return Z;
}
void Init(){
scanf("%d %d", &n, &m);
scanf("%u %u %u", &X, &Y, &Z);
for(int i = 1; i <= m; i++){
int p = getnum() % n + 1, q = getnum() % n + 1;
int l = min(p, q);
int r = max(p, q);
LL v = getnum() % INF;
int d = Log2[r-l+1];
Line[l][d] = max(Line[l][d], (LL)v);
Line[r-pow2[d] + 1][d] = max(Line[r-pow2[d] + 1][d], (LL)v);
}
}
void Solve(){
for(int d = 30; d >= 1; d--){
for(int i = 1; i +pow2[d] <= n+1; i++){
Line[i][d-1] = max(Line[i][d-1], Line[i][d]);
Line[i+pow2[d-1]][d-1] = max(Line[i+pow2[d-1]][d-1], Line[i][d]);
Line[i][d] = 0LL;
}
}
LL ans = 0LL;
for(int i = 1; i <= n; i++){
ans = ans ^ ((LL)i * Line[i][0]);
Line[i][0] = 0LL;
}
printf("%lld\n", ans);
}
int main()
{
Log2[0] = -1;
pow2[0] = 1;
for(int i = 1; i <= 30; i++) pow2[i] = pow2[i-1] * 2;
for(int i = 1; i <= MAXN; i++) Log2[i] = Log2[i >> 1] + 1;
int T; scanf("%d", &T);
while(T--){
Init();
Solve();
}
return 0;
}