트 리 세트 트 리 - 구간 k 대 (수정 띠)
7069 단어 ACM-데이터 구조ACM - 모델의장 수나무
제목: 구간 k 의 큰 수 를 구하 고 수정 작업 이 있 습 니 다.
분석: 이 문 제 는 나무 로 만 들 수 있다.
인터넷 에서 블 로 그 를 많이 보고 나 서 야 이해 하 는데...자료 자료
내 가 본 것 은 나무 모양 배열 의 선분 트 리 판 이다.그리고 선분 트 리 밸 런 스 트 리.
우선 주석 트 리 로 조작 전의 데 이 터 를 유지 합 니 다.
그리고 트 리 배열 로 수정 합 니 다.
나무 모양 배열 의 모든 노드 는 선분 나무 이 고 나무 모양 배열 의 모든 노드 는 하나의 관할 구역 (나무 모양 배열 의 성질 은 변 하지 않 았 다) 이 있다.
매번 업데이트 할 때마다 log (n) 트 리 배열 의 노드 를 수정 합 니 다.그러나 수정 은 바람 직 하지 않 기 때문에 log (n) 그루 의 선분 나 무 를 새로 만 드 는 방법 을 사용 했다.
새로 만 든 선분 트 리 는 원래 버 전의 선분 트 리 를 먼저 복사 한 다음 에 수정 할 경 로 를 대체 하 는 경로 (log (n) 노드 추가) 를 추가 하 는 것 입 니 다.
코드 (트 리 배열 라인 트 리):
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1e5+6;
const int LOG = 20;
struct node
{
int l,r;
int sum;
}Node[maxn*LOG];
int root[maxn],node_cnt; // ,
int BIT[maxn]; //
int numbers[maxn],num_cnt; //
int a[maxn],n,q;
struct command
{
char op;
int L,R,K;
}com[10006];
void build(int l,int r,int &rt)
{
rt=++node_cnt;
Node[rt].sum=0;
if(l==r) return ;
int m=l+r>>1;
build(l,m,Node[rt].l);
build(m+1,r,Node[rt].r);
}
void update(int pos,int v,int l,int r,int &rt,int pre)
{
rt=++node_cnt;
Node[rt]=Node[pre];
Node[rt].sum+=v;
if(l==r) return ;
int m=(l+r)>>1;
if(pos<=m)
update(pos,v,l,m,Node[rt].l,Node[pre].l);
else
update(pos,v,m+1,r,Node[rt].r,Node[pre].r);
}
void modify(int pos,int v,int rt)
{
for(int i=rt;i>1;
if(k<=c)
return query(k,l,m);
else
return query(k-c,m+1,r);
}
inline int Find(int x)
{
return lower_bound(numbers+1,numbers+1+num_cnt,x)-numbers;
}
void Q(int L,int R,int K)
{
buf_cnt1=0;
buf1[buf_cnt1++]=root[L-1];
for(int i=L-1;i>0;i-=(i&-i))
buf1[buf_cnt1++]=BIT[i];
buf_cnt2=0;
buf2[buf_cnt2++]=root[R];
for(int i=R;i>0;i-=(i&-i))
buf2[buf_cnt2++]=BIT[i];
int q=query(K,1,num_cnt);
printf("%d
",numbers[q]);
}
void C(int pos,int v)
{
modify(Find(a[pos]),-1,pos);
modify(Find(v),1,pos);
a[pos]=v;
}
int main()
{
int nCase;
scanf("%d",&nCase);
while(nCase--)
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
numbers[i]=a[i];
}
num_cnt=n;
char ch[2];
for(int i=1;i<=q;i++)
{
scanf("%s",ch);
if(ch[0]=='Q')
{
scanf("%d%d%d",&com[i].L,&com[i].R,&com[i].K);
com[i].op='Q';
}
else
{
scanf("%d%d",&com[i].L,&com[i].R);
com[i].op='C';
numbers[++num_cnt]=com[i].R;
}
}
sort(numbers+1,numbers+num_cnt+1);
num_cnt=unique(numbers+1,numbers+num_cnt+1)-numbers-1;
root[0]=node_cnt=0;
build(1,num_cnt,root[0]);
for(int i=1;i<=n;i++)
{
int f=Find(a[i]);
update(f,1,1,num_cnt,root[i],root[i-1]);
}
for(int i=1;i<=n;i++) // ,
BIT[i]=root[0];
for(int i=1;i<=q;i++)
'Q'==com[i].op?Q(com[i].L,com[i].R,com[i].K):C(com[i].L,com[i].R);
}
return 0;
}
선분 트 리 세트 reap 은 메모 리 를 초과 합 니 다. 저 는 동적 으로 메모 리 를 분배 합 니 다. 삭제 할 때 도 delete 했 습 니 다.최대 n * log (n) 개의 node, 즉 5 * 50000 * 16 개의 int (32000 * 1000 bit) 를 사 용 했 고 별도로 연 두 배열 20000 개의 int (1600 * 1000 bit) 를 더 해 총 32813 kb 로 방금 초과 했다.
해법
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
struct node // Treap
{
node* son[2]; //
int v; //
int p; //
int sz; //
node(int x)
{
son[0]=son[1]=NULL;
v=x;
p=rand();
sz=1;
}
void pushup() // sz
{
sz=1;
if(son[0]) sz+=son[0]->sz;
if(son[1]) sz+=son[1]->sz;
}
};
inline int cmp(int a,int b)
{
if(a==b) return -1;
return a>b?0:1;
}
inline void Rotate(node* &root,int d) //d 0 ( ), d 1 ( )
{
node* k = root->son[d^1];
root->son[d^1] = k->son[d] ;
k->son[d] = root;
root->pushup();
k->pushup();
root = k ;
}
void Insert(node* &root,int x)
{
if(NULL==root)
root = new node(x);
else
{
int d = root->v>x?0:1; //
Insert(root->son[d],x);
if(root->pson[d]->p)
Rotate(root,d^1);
}
if(root)
root->pushup();
}
void Erase(node* &root,int x)
{
int d = cmp(root->v,x);
if(-1==d)
{
node* u = root;
if(!root->son[0])
{
root = root->son[1];
delete u;
}
else if(!root->son[1])
{
root = root->son[0];
delete u;
}
else
{
int d2 = (root->son[0]->p>root->son[1]->p?1:0);
Rotate(root,d2);
Erase(root->son[d2],x);
}
}
else
Erase(root->son[d],x);
if(root)
root->pushup();
}
void Destroy(node* &root)
{
if(root->son[0])
Destroy(root->son[0]);
if(root->son[1])
Destroy(root->son[1]);
delete root;
root=NULL;
}
int Find(node* root,int x)
{
if(NULL==root)
return 0;
int ret=0,lnum=0;
if(root->son[0])
lnum+=root->son[0]->sz;
if(x>=root->v)
return lnum+1+Find(root->son[1],x);
else
return Find(root->son[0],x);
}
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50006;
node* tree[151000];
int a[maxn],n,m;
void update(int pos,int v,int d,int l,int r,int rt)
{
d==1?Insert(tree[rt],v):Erase(tree[rt],v);
if(l==r) return ;
int m=(l+r)>>1;
pos<=m?update(pos,v,d,lson):update(pos,v,d,rson);
}
int query(int L,int R,int x,int l,int r,int rt)
{
if(L<=l && r<=R)
return Find(tree[rt],x);
int m=(l+r)>>1,ret(0);
if(L<=m)
ret+=query(L,R,x,lson);
if(R>m)
ret+=query(L,R,x,rson);
return ret;
}
int work(node* root,int x)
{
int ret=INF;
while(root)
{
if(root->v>=x)
{
if(ret>root->v)
ret=root->v;
root=root->son[0];
}
else
root=root->son[1];
}
return ret;
}
int q(int L,int R,int x,int l,int r,int rt)
{
if(L<=l && r<=R)
return work(tree[rt],x);
int m=(l+r)>>1,ret=INF;
if(L<=m)
ret=min(ret,q(L,R,x,lson));
if(R>m)
ret=min(ret,q(L,R,x,rson));
return ret;
}
void Q(int L,int R,int K)
{
int down=-INF,up=INF,mid,ret;
while(down>1;
// printf("%d
",mid);
int c=query(L,R,mid,1,n,1);
if(c>=K)
up=mid;
else
down=mid+1;
}
printf("%d
",q(L,R,down,1,n,1));
}
void C(int pos,int v)
{
update(pos,a[pos],0,1,n,1);
update(pos,v,1,1,n,1);
a[pos]=v;
}
int main()
{
int nCase;
scanf("%d",&nCase);
while(nCase--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=0;i
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
HDU 6325 Interstellar Travel [돌출]제목 링크 After trying hard for many years, Little Q has finally received an astronaut license. Little Q knows the position ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.