已知數列p是1~n的排列,現在給定m組詢問,每組詢問給出左右端點l和r,求出[l,r]區間中有多少對滿足p[i]%p[j]=0 或 p[j]%p[i]=0
,要求i首先維護乙個字首和sum,其中sum[i]維護的是[1,i]中滿足條件的對數。
那麼對於詢問[l,r],結果就是sum[r]-sum[l-1]。
但是這看上去有些問題,因為存在i在[1,l-1],j卻在[l,r]上的情況。
於是我們用乙個樹狀陣列來維護這種情況,在查詢完乙個左端點l後,將它所有的倍數(除了它自己)全都更新,每次查詢結果減去ask®-ask(l-1)。
舉個例子,樣例為
5 2第一次查詢完成後,樹狀陣列會在[2,5]區間上都+1,表示這些是1的倍數。在去查[3,5]區間時,就會減去這些值。1 2 3 4 5
1 53 5
**寫的有些醜陋,因為之前讀錯題了套了乙個莫隊的板子,多了乙個f結構體陣列,其實用不到。
#include
using
namespace std;
const
int maxn =
100005
;typedef
long
long ll;
template
<
class
t>
void
read
(t &x)
while
(s>=
'0'&&s<=
'9')
x *= f;
}struct node
bool
operator
<
(const node &b)
const};
int block;
struct node2
}f[maxn]
;int c[maxn]
,a[maxn]
,ans2[maxn]
,n,m,res,pos[maxn]
,sum[maxn]
,cnt[maxn]
,cnt[maxn]
,ans[maxn]
;vector<
int> e[maxn]
;vector q[maxn]
;int
lowbit
(int x)
void
update
(int x)
intask
(int x)
intmain()
for(
int i=
1;i<=n;i++)}
for(
int i=
1;i<=n;i++
)sort
(e[i]
.begin()
,e[i]
.end()
);for(
int i=
1;i<=n;i++
) sum[i]
= sum[i-1]
+ cnt[i]
;for
(int i=
1;i<=n;i++
)int temp =
upper_bound
(e[i]
.begin()
,e[i]
.end()
,i)- e[i]
.begin()
;for
(int j=temp;j.size()
;j++
)update
(e[i]
[j]);}
for(
int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]
-(f[i]
.r-f[i]
.l+1))
;// for(int i=1;i<=m;i++) cout << ans2[i] << ' ';
return0;
}
2019徐州網路賽 query
題目鏈結 題解,這個題目巧妙地按下標進行樹狀陣列處理,先預處理所有有倍數關係的和每個元素的位置i,然後把下標小的存到下標大 的陣列中,查詢也離線,然後從左到右,邊加入,邊求和。include include include using namespace std int n int sum 1000...
2019ICPC徐州網路賽
theme n個數編號為1 n,兩種操作 1 x 將編號為x的數置為不可得,2 x 詢問x位置及其後第乙個可得數的編號。1 n,x 1e9,1 q 1e6 solution 首先想到用線段樹維護。初始時線段樹每個l r位置的值為l,1 x操作對應將x位置值置為inf,2 x 操作相當於查詢區間 x,...
2018徐州網路賽
a.hard to prepare dp 題目 題意 環形圈中,給每人乙個號碼,求使得相鄰數字反異或為正數的方案數。有題意可推出,每兩個數反異或要麼是0要麼是正數,所以也就是讓相鄰數字反異或後不能為0。又知道,與某個數反異或之後為0的只有唯一乙個數,因此可推出第1個人到第n個人分別可選的數的個人為 ...