[GDOI 시 뮬 레이 션 2016.03.05] 마도 연구
t 개 를 재 집합 할 수 있 는 Ti 를 지정 합 니 다. i 개 에서 전 i 대 를 재 집중 적 으로 선택 하여 재 집합 S 를 구성 할 수 있 습 니 다.m 개의 조작 이 있 는데 두 가지 로 나 뉘 는데 그것 이 바로 t 집합 에 특정한 요 소 를 삭제 하거나 t 집합 에 특정한 요 소 를 추가 하 는 것 이다.매번 조작 후 S 의 앞 n 대 를 유지 합 니 다.
m, n, t ≤ 300000, 모든 원 소 는 109 보다 크 지 않 은 정수 입 니 다.
제목 분석
분명히 우 리 는 데이터 구 조 를 이용 하여 T 집합 과 S 집합 을 유지 할 수 있다.동작 을 추가 할 때, 우 리 는 대응 하 는 Ti 집합 에 이 수 를 삽입 하여 랭 킹 을 조회 합 니 다.만약 rank < = i 가 하나의 수 를 밀 어 냈 다 는 것 을 설명 한다 면, 우 리 는 Ti 가 집합 한 i + 1 명 을 S 에서 삭제 하고 마지막 으로 S 에 새 수 를 추가 하면 됩 니 다.삭제 작업 이 유사 합 니 다.이 데이터 구 조 는 밸 런 스 트 리, 짝 짓 기 등 을 선택 할 수 있다.사실 가중치 선분 트 리 는 문 제 를 해결 할 수 있 고 구체 적 인 과정 은 동태 적 인 개방 점 이 필요 하 다.
코드 구현
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long LL;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch))
{
if (ch=='-')
f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int S=40000005;
const int N=300005;
const int M=300005;
const int T=300005;
const int P=1000000000;
int n,m;
struct tree
{
int son[S][2],size[S];
int root[T];
LL sum[S];
int tot;
int newnode()
{
size[++tot]=0;
son[tot][0]=son[tot][1]=sum[tot]=0;
return tot;
}
void init()
{
memset(size,0,sizeof size);
memset(sum,0,sizeof sum);
memset(son,0,sizeof son);
tot=0;
for (int i=0;i<=300000;i++)
root[i]=newnode();
}
int kth(int rt,int rk,int l,int r)
{
if (l==r)
return l;
int mid=l+r>>1;
if (size[son[rt][1]]>=rk)
return kth(son[rt][1],rk,mid+1,r);
rk-=size[son[rt][1]];
return kth(son[rt][0],rk,l,mid);
}
int rank(int rt,int x,int l,int r)
{
if (l==r)
return 1;
int mid=l+r>>1;
if (x>mid)
return rank(son[rt][1],x,mid+1,r);
else
return size[son[rt][1]]+rank(son[rt][0],x,l,mid);
}
int change(int rt,int x,int l,int r,int delta)
{
if (!rt)
rt=newnode();
if (l==r)
{
sum[rt]+=delta*1ll*x;
size[rt]+=delta;
return rt;
}
int mid=l+r>>1;
if (x<=mid)
son[rt][0]=change(son[rt][0],x,l,mid,delta);
else
son[rt][1]=change(son[rt][1],x,mid+1,r,delta);
int ls=son[rt][0],rs=son[rt][1];
sum[rt]=sum[ls]+sum[rs];
size[rt]=size[ls]+size[rs];
return rt;
}
LL query(int rt,int kth,int l,int r)
{
if (l==r)
return l*1ll*min(kth,size[rt]);
int mid=l+r>>1;
if (kth<=size[son[rt][1]])
return query(son[rt][1],kth,mid+1,r);
else
return sum[son[rt][1]]+query(son[rt][0],kth-size[son[rt][1]],l,mid);
}
}t;
int main()
{
freopen("grimoire.in","r",stdin);
freopen("grimoire.out","w",stdout);
n=read(),m=read();
t.init();
for (int i=1;i<=m;i++)
{
char cmd=getchar();
while (!isalpha(cmd))
cmd=getchar();
int ti=read(),pi=read();
if (cmd=='B')
{
t.change(t.root[ti],pi,1,P,1);
int rk=t.rank(t.root[ti],pi,1,P);
if (rk<=ti)
{
if (t.size[t.root[ti]]>ti)
{
int num=t.kth(t.root[ti],ti+1,1,P);
t.change(t.root[0],num,1,P,-1);
}
t.change(t.root[0],pi,1,P,1);
}
LL ans=t.query(t.root[0],n,1,P);
printf("%lld
",ans);
}
else
{
int rk=t.rank(t.root[ti],pi,1,P);
t.change(t.root[ti],pi,1,P,-1);
if (rk<=ti)
{
if (t.size[t.root[ti]]>=ti)
{
int num=t.kth(t.root[ti],ti,1,P);
t.change(t.root[0],num,1,P,1);
}
t.change(t.root[0],pi,1,P,-1);
}
LL ans=t.query(t.root[0],n,1,P);
printf("%lld
",ans);
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.