【2018 Multi-University Training Contest 2 1007】Naive Operations
阿新 • • 發佈:2018-07-26
min out ans ack ive txt 題解 syn class
【鏈接】 我是鏈接,點我呀:)
【題意】
給你兩個數組a,b;
b數組是1..n的一個排列。
現在給你兩種操作:
add l,r將a[l..r]都加上1
query l,r 詢問$∑^r_l\frac{ai}{bi} $
其中a[i]/b[i]是下取整。
n<=10^5
【題解】
很優秀的題
我們可以在線段樹1中維護所有a[i]/b[i]的值
想一下何時我們才要讓線段樹1中的值改變?
必然是我們一直加a的值,讓a[i]的值超過了b[i]
設讓線段樹中的值改變操作為操作x
那麽操作x最多湖執行多少次呢?
a最多變成10^5
那麽就是
∑10^5/b[i] ,又b是一個排列
那麽原式即\(10^5*(1/1+1/2+1/3+...+1/n)\)
其中右邊那個式子是logn級別的。
那麽總共要進行的操作x的次數就約等於nlogn
那麽我們可以這麽做。
另外開一個線段樹2.
這個線段樹一開始每個位置上的值為b[i]
我們可以維護一下區間最小值。
然後每次add(l,r)對應地把線段樹2中相應位置遞減1.
直到發現某個位置變成0了(最小值變成0就說明有些位置變成0了
那麽就把線段樹1中對應的a[i]/b[i]的值遞增1.
然後再把那個位置重置為對應的b[i]就可以了。
根據上面的分析,這個遞增操作次數最多nlogn次。
query操作直接就是線段樹1的區間求和問題了。很輕松就能解決。
【代碼】
#include <bits/stdc++.h> #define LL long long #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define rep1(i,a,b) for (int i = a;i<= b;i++) using namespace std; const double pi = acos(-1); const int dx[4] = {0,0,1,-1}; const int dy[4] = {1,-1,0,0}; const int N = 1e5; int a[N+10],b[N+10],mi[N*4+10],tag[N*4+10],sum2[N*4+10]; int n,q; char s[8]; void _updata2(int l,int r,int rt,int pos){ if (l==r){ sum2[rt]++; return; } int mid = (l+r)>>1; if (pos<=mid) _updata2(lson,pos); else _updata2(rson,pos); sum2[rt] = sum2[rt<<1]+sum2[rt<<1|1]; } void push_down(int rt){ if (tag[rt]>0){ tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt]; mi[rt<<1]-=tag[rt];mi[rt<<1|1]-=tag[rt]; tag[rt] = 0; } } void _find0(int l,int r,int rt){ if (l==r){ _updata2(1,n,1,l); mi[rt] = b[l]; return; } push_down(rt); int mid = (l+r)>>1; if (mi[rt<<1]==0) _find0(lson); if (mi[rt<<1|1]==0)_find0(rson); mi[rt]= min(mi[rt<<1],mi[rt<<1|1]); } void _updata1(int l,int r,int rt,int L,int R){ if (L<=l && r<=R){ mi[rt]--; tag[rt]++; if (mi[rt]==0){ _find0(l,r,rt); } return; } push_down(rt); int mid = (l+r)>>1; if (L<=mid) _updata1(lson,L,R); if (mid<R) _updata1(rson,L,R); mi[rt] = min(mi[rt<<1],mi[rt<<1|1]); } long long get_ans2(int l,int r,int rt,int L,int R){ if (L<=l && r <= R) return sum2[rt]; int mid = (l+r)>>1; long long temp1 = 0,temp2 = 0; if (L<=mid) temp1 = get_ans2(lson,L,R); if (mid<R) temp2 = get_ans2(rson,L,R); return temp1+temp2; } void build1(int l,int r,int rt){ tag[rt] = 0; int mid = (l+r)>>1; if (l==r){ mi[rt] = b[l]; return; } if (l<=mid) build1(lson); if (mid<r) build1(rson); mi[rt] = min(mi[rt<<1],mi[rt<<1|1]); } int main(){ #ifdef LOCAL_DEFINE freopen("rush_in.txt", "r", stdin); #endif ios::sync_with_stdio(0),cin.tie(0); while (cin >> n >> q) { memset(a,0,sizeof a); memset(sum2,0,sizeof sum2); rep1(i,1,n) cin >> b[i]; build1(1,n,1); while (q--) { int ll,rr; cin >> s >> ll >> rr; if (s[0]=='a') _updata1(1,n,1,ll,rr); else cout<<get_ans2(1,n,1,ll,rr)<<endl; } } return 0; }
【2018 Multi-University Training Contest 2 1007】Naive Operations