一、题目描述:
给你一个长度为 $n$ 的序列 $a$ , 你需要进行 $q$ 次操作。
$将第\ x\ 个元素的值修改为\ v\ 。$
每次操作后,输出序列前 $k$ 大的元素和
数据范围:$1 \le n,q \le 5 \times 10^5 ,所有数\ -10^9 \le val \le 10^9$
二、解题思路:
用两个 $set$ 维护,$s1$ 维护前 $k$ 大,$s2$ 维护非前 $k$ 大 。
每次将 $s2$ 中最大的与 $s1$ 中最小的进行比较,若能更大就交换。
好奇妙的思路啊!不愧是 $jiangly$ ! $orz$ 。时间复杂度 $O(nlog_2^n)$ 。
三、完整代码:
1 #include<iostream> 2 #include<set> 3 #define N 500010 4 #define ll long long 5 using namespace std; 6 multiset <ll> s1,s2; 7 ll n,k,q,x,y,ans,a[N]; 8 int main() 9 { 10 ios::sync_with_stdio(false); 11 cin.tie(0);cout.tie(0); 12 cin>>n>>k>>q; 13 for(ll i=1;i<=n;i++) 14 if(i<=k) s1.insert(a[i]); 15 else s2.insert(a[i]); 16 for(ll i=1;i<=q;i++) 17 { 18 cin>>x>>y; 19 ll t=y-a[x]; 20 if(k==n) 21 { 22 a[x]=y;ans+=t; 23 cout<<ans<<'\n'; 24 continue; 25 } 26 auto iter1=s1.find(a[x]); 27 auto iter2=s2.find(a[x]); 28 if(iter1!=s1.end()) 29 s1.erase(iter1),s1.insert(y),ans+=t; 30 else s2.erase(iter2),s2.insert(y); 31 a[x]=y;iter1=s1.begin(); 32 iter2=s2.end(); iter2--; 33 x=*iter1,y=*iter2,t=y-x; 34 while(t>0) 35 { 36 ans+=t; 37 s1.erase(iter1),s1.insert(y); 38 s2.erase(iter2),s2.insert(x); 39 iter1=s1.begin(); 40 iter2=s2.end();iter2--; 41 x=*iter1,y=*iter2,t=y-x; 42 } 43 cout<<ans<<'\n'; 44 } 45 return 0; 46 }
四、写题心得:
$set$中位置的访问相对繁琐,但也不是很难。收获经验如下:
$1、set\ 好像很难确定某个元素的位置呢。=> Exp++!$
$2、访问\ set\ 中最后一个元素可以用\ auto\ iter = s.end() , iter--\ 。=> Exp++$
浙公网安备 33010602011771号