題目大意:
給乙個1-n的排列,然後詢問[x,y]區間中有多少個連續的段。
如給乙個3 1 2 5 4, 查詢是2 4,那麼就是問1 2 5中有多少個連續的串,一共有兩個串,1、2為乙個串,5為乙個串
若查詢是2 5,則問的是1 2 5 4中有多少個連續的串,一共有兩個串, 1、2為乙個串, 4、5 為乙個串。
反思:這一題我想了蠻久的,因為我一直想要去維護每乙個串的首個數字,但想了很久都沒有想到維護的方法。
後面看了題解後才發現,不僅僅可以通過數串數得到答案,還可以通過一段區間中有多少個相鄰的數字對,來得到答案。
若查詢區間中有k個相鄰數字對,區間長度是m,那麼這次的答案就是m - k。
這個其實蠻好理解的,大家舉幾個例子仔細想一下就明白了。
像1 2 5 4,其中1和2、4和5是相鄰的數字對,所以答案就是 4 - 2 = 2
現在問題就變成了求一段區間當中有多少個相鄰的數字對。
我的解決方法是進行離線查詢,對m個詢問按照x的大小,從大到小排序,然後根據查詢,依次更新區間[n, n], [n-1, n]. [n-2, n] , [n-3, n], [n-4, n] ........ [2, n], [1, n]的數字對的情況:
具體更新方法:從[i+1, n]更新到[i, n],若pos[a[i]+1] > i , 則updata(pos[a[i]+1], 1)。若pos[a[i]-1] > i ,則updata(pos[a[i-1]]. 1)。否則不進行操作。
具體更新**
void updata(int val, int posx)
j = n + 1;
for (i=m; i>=1; i--)
ans[q[i].id] = (q[i].y - q[i].x + 1) - query(q[i].x, q[i].y);
}
在這個更新基礎上,查詢就只要直接用樹狀陣列查詢區間合就好了。
最後附上全部**:
#include #include #include #include using namespace std;
const int maxn = 1e5 + 100;
class query
;bool operator < (const query &a, const query &b)
query q[maxn];
int a[maxn], pos[maxn], ans[maxn], h[maxn];
int n, m;
int lowbit(int x)
void updata_tree(int x, int val)
return;
}int query_tree(int x)
return ans;
}void updata(int val, int posx)
int query(int x, int y)
int main()
for (i=1; i<=m; i++)
sort(q+1, q+m+1);
j = n + 1;
for (i=m; i>=1; i--)
ans[q[i].id] = (q[i].y - q[i].x + 1) - query(q[i].x, q[i].y);
} for (i=1; i<=m; i++)
printf("%d\n", ans[i]);
} return 0;
}
hdu 4638 Group 樹狀陣列
題意 找到區間裡有多少組連續數字串 分析 思路 顯然,我們要使得value最大,就要盡量將連續的id分在一組,所以問題轉化為求乙個區間中連續id區間的個數。我們從左往右掃瞄,依次考慮右端點為i的詢問,設dp l 為區間 l,i 的連續區間個數,po i 為i出現的位置,若還未出現,則為0,設我們當前...
HDU 4638 Group 樹狀陣列
詢問一段區間裡的數能組成多少段連續的數。先考慮從左往右乙個數乙個數新增,考慮當前新增了i 1個數的答案是x,那麼可以看出新增完i個數後的答案是根據a i 1和a i 1是否已經新增而定的 如果a i 1或者a i 1已經新增乙個,則段數不變,如果都沒新增則段數加1,如果都新增了則段數減1。設v i ...
Hdu 4638 Group 離線 樹狀陣列
題目大意 給你1 n的任意全排列,詢問q次,每次詢問區間 l r 內的組數,組數的定義為 在乙個連續區間中,可以把區間中的數任意分成幾組,每組的所有數必須連續,比如 7 5 8的組數為2,即7,8和5。解題思路 先假設每個數都是一組,然後查詢和他相鄰的兩個數是否在此之前出現過,如果出現則 出現的位置...