一、题目描述:

  给你一个长度为 $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++$

 

posted on 2023-06-18 16:04  trh0630  阅读(19)  评论(0)    收藏  举报