Codeforces 85D Sum of Medians(线段树)

题目链接:D. Sum of Medians

题意:给定一个空数组,每次进行以下操作

1.增加一个[1,10^9]内的数(该数保证不在数组中)

2.删除一个[1,10^9]内的数(该数保证在数组中)

3.求数组排序后数组内下标对5取余等于3的元素和

题解:将下标离散化,我们可以用线段树维护区间内数的个数,以及下标对5取余后对应0-4的元素的和,每次询问时答案就是t[rt][1]=v;,修改也很简单,注意在合并部分,合并时,右区间内对5取余后的下标在合并后变为(左区间个数+i)%5,左区间内保持不变,细节见代码

代码(注释很详细,不懂可以看注释):

#include<iostream>
#include<stack>
#include<list>
#include<set>
#include<vector>
#include<algorithm>
#include<math.h>
#include<numeric>
#include<map>
#include<cstring>
#include<queue>
#include<iomanip>
#include<cmath>
#include<queue>
#include <bitset>
#include<unordered_map>/*
	#ifndef local
	#define endl '\n'
#endif */
#define mkp make_pair
using namespace std;
using std::bitset;
typedef long long ll;
typedef long double ld;
const int inf=0x3f3f3f3f;
const ll MAXN=2e6+10;
const ll N=1e6+100;
const ll mod=998244353;
const ll hash_p1=1610612741;
const ll hash_p2=805306457;
const ll hash_p3=402653189;
//-----------------------------------------------------------------------------------------------------------------*/
// ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
/* 
void add(ll u,ll v,ll w,ll s){
	to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
	to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
}
struct elemt{
	int p,v;
};
struct comp{
	public:
		bool operator()(elemt v1,elemt v2){
			return v1.v<v2.v;
		}
};
-----------------------------------
求[1,MAXN]组合式和逆元 
ll mi(ll a,ll b){
	ll res=1;
	while(b){
		if(b%2){
			res=res*a%mod;
		}	
		a=a*a%mod;
	}
	return res;
}
ll fac[MAXN],inv[MAXN]
fac[0]=1;inv[0]=1;
for(int i=1;i<=MAXN;i){
	fac[i]=(fac[i-1]*i)%mod;
	inv[i]=mi(fac[i],mod-2);
}
ll C(int m,int n){//组合式C(m,n); 
	if(!n){
		return 1;
	}
	return fac[m]*(inv[n]*inv[m*-n]%mod)%mod;
}
---------------------------------
 unordered_map<int,int>mp;
//优先队列默认小顶堆 , greater<int> --小顶堆  less<int> --大顶堆  
priority_queue<elemt,vector<elemt>,comp>q;
	set<int>::iterator it=st.begin();
*/
// vector<vector<int>>edge; 二维虚拟储存坐标 
//-----------------------------------------------------------------------------------------------------------------*/
  map<int,int>mp; 
int lei[N],x[N];//操作类别和 操作的x
vector<int>a;//离散化存数据
int cnt=0;//离散化后数据下标
void init(){
	sort(a.begin(),a.end());
	int tot=unique(a.begin(),a.end())-a.begin();
	for(int i=0;i<tot;i++){
		mp[a[i]]=++cnt;
	}
}
ll t[N][5];//线段树对应区间内下标对5取余的值的和
int num[N];//线段树对应区间内数的个数,用于合并时判断
void pushin(int rt){//区间合并操作
	memset(t[rt],0,sizeof(t[rt]));
	for(int i=0;i<5;i++){
		t[rt][i]+=t[2*rt][i];
		t[rt][(i+num[2*rt])%5]+=t[2*rt+1][i];//右区间内对5取余后的下标在合并后变为(左区间个数+i)%5
	}
	num[rt]=num[2*rt]+num[2*rt+1];
}
void update(int l,int r,int rt,int p,int k,int v){
	if(l==r){
		num[rt]=0;
		t[rt][1]=0;
		if(k==1){//增加操作
			t[rt][1]=v;
			num[rt]=1;
		}
		return ;
	}
	int mid=(l+r)/2;
	if(p<=mid){
		update(l,mid,2*rt,p,k,v);
	}
	else{
		update(mid+1,r,2*rt+1,p,k,v);
	}
	pushin(rt);
}
int main(){
/*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
/*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
int n;
cin>>n;	
for(int i=1;i<=n;i++){
	string s;
	cin>>s;
	if(s=="add"){
		lei[i]=1;
		cin>>x[i];
		a.push_back(x[i]);
	}
	else if(s=="del"){
		lei[i]=2;
		cin>>x[i];
		a.push_back(x[i]);
	}
	else{
		lei[i]=3;
	}
} 
init();//离散化
for(int i=1;i<=n;i++){
	if(lei[i]==3){
		cout<<t[1][3]<<endl;
	}
	else if(lei[i]==1){
		update(1,cnt,1,mp[x[i]],1,x[i]);
	}
	else{
		update(1,cnt,1,mp[x[i]],-1,x[i]);
	}
}
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值