1. 程式人生 > >HDU 5919 Sequence II ( 主席樹 )

HDU 5919 Sequence II ( 主席樹 )

c++ query == %d 都是 基本 RR std splay

題意 : 給出 N 個數、然後 M 個問詢、問詢格式是給出 ( L、R ) 然後需要根據規則變成新的 ( L‘、R‘ ) [ 即此題強制在線了 ]、對於每個問詢假設問詢區間內有 X 個不同種類的數、每個數從左到右第一次出現的位置是 pos1、pos2... posX 然後要你給出 pos( (X+1)/2 ) 是多少

分析 :

主要就是查詢區間內不同數的個數、區間內第 K 大

這兩個都是主席樹的基本功能、所以考慮使用主席樹來做

從左到右對於每個前綴可持久化建樹、然後對於每個區間問詢先查出有多少個不同種類的數

然後再二分位置、把第 (X+1)/2 個找出來就是答案了。

但是二分會多出一個 log 、這裏可以有避免二分的辦法、需要一個技巧

就是從右往左建樹、然後對於問詢、就可以直接 log 地查詢 K 大值了

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
struct NODE{
    int sum, L, R;
    NODE(){};
    NODE(int _sum, int _L, int _R):
        sum(_sum),L(_L),R(_R){};
}T[maxn*40]; int Tcnt = 0;

int root[maxn];
int arr[maxn], N;

int newNode(int
sum, int L, int R) { T[++Tcnt] = NODE(sum, L, R); return Tcnt; } inline void Insert(int &root, int pre, int pos, int val, int L, int R) { root = newNode(T[pre].sum+val, T[pre].L, T[pre].R); if(L == R) return ; int M = L + ((R-L)>>1); if(pos <= M) Insert(T[root].L, T[pre].L, pos, val, L, M);
else Insert(T[root].R, T[pre].R, pos, val, M+1, R); } int query(int rt, int pos, int L, int R) { if(L == R) return T[rt].sum; int ret = 0; int M = L + ((R-L)>>1); if(pos <= M) ret += query(T[rt].L, pos, L, M); else ret += query(T[rt].R, pos, M+1, R) + T[T[rt].L].sum; return ret; } int Kth(int K, int rt, int l, int r) { if(l == r) return l; int m = l + ((r-l)>>1); if(T[T[rt].L].sum >= K) return Kth(K, T[rt].L, l, m); else return Kth(K-T[T[rt].L].sum, T[rt].R, m+1, r); } map<int, int> mp; int main(void) { int nCase; scanf("%d", &nCase); for(int Case=1; Case<=nCase; Case++){ mp.clear(); printf("Case #%d:", Case); T[0] = NODE(0, 0, 0); root[N+1] = 0; Tcnt = 0; scanf("%d", &N); int Q; scanf("%d", &Q); for(int i=1; i<=N; i++) scanf("%d", &arr[i]); for(int i=N; i>=1; i--){ if(mp.count(arr[i])){ int tmpRoot; Insert(tmpRoot, root[i+1], i, 1, 1, N); Insert(root[i], tmpRoot, mp[arr[i]], -1, 1, N); }else Insert(root[i], root[i+1], i, 1, 1, N); mp[arr[i]] = i; } int PreAns = 0; while(Q--){ int l, r; scanf("%d %d", &l, &r); int A = (l+PreAns)%N+1; int B = (r+PreAns)%N+1; l = min(A, B); r = max(A, B); if(l > r) swap(l, r); int K = ( query(root[l], r, 1, N) + 1 ) / 2; //// 註釋部分為二分寫法 // int L = l, R = r, ans; // while(L <= R){ // int M = L + ((R-L)>>1); // if(query(root[l], M, 1, N) >= K) R = M-1, ans = M; // else L = M+1; // } // printf(" %d", PreAns = ans); printf(" %d", PreAns = Kth(K, root[l], 1, N)); }puts(""); } return 0; }
View Code

HDU 5919 Sequence II ( 主席樹 )