bzoj2120(帶修改莫隊 或 樹狀數組套主席樹)

做法一:

 

帶修改莫隊模板

第一關鍵字:左端點的塊

第二:右端點塊

第三:前面的修改次數,這裏稱time

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10005;

int n,m;
int block,pos[N],col[N];

int query_num;
struct aa
{
	int l,r,time,id,ans;
	bool operator <(const aa &b)const
	{
		if (pos[l]!=pos[b.l]) return pos[l]<pos[b.l];
		if (pos[r]!=pos[b.r]) return pos[r]<pos[b.r];
		return time<b.time;
	}
}a[N];
bool cmp(aa a,aa b)
{
	return a.id<b.id;
}

int time;
struct bb
{
	int x,y,z;
}q[N];

int tt[N*100],tmp,l,r,now;

void insert(int pos)
{
	tt[col[pos]]++;
	if (tt[col[pos]]==1) tmp++;
}
void del(int pos)
{
	tt[col[pos]]--;
	if (tt[col[pos]]==0) tmp--; 
}

void in_time(int i)
{
	int pos=q[i].x,to=q[i].y,&from=q[i].z;
	if (pos>=l&&pos<=r) del(pos);
	from=col[pos];
	col[pos]=to;
	if (pos>=l&&pos<=r) insert(pos);
}
void out_time(int i)
{
	int pos=q[i].x,to=q[i].y,from=q[i].z;
	if (pos>=l&&pos<=r) del(pos);
	col[pos]=from;
	if (pos>=l&&pos<=r) insert(pos);
}

void work()
{
	l=1,r=0,now=0;
	for (int i=1;i<=query_num;i++)
	{
		for (;r<a[i].r;r++) insert(r+1);
		for (;r>a[i].r;r--) del(r);
		
		for (;l<a[i].l;l++) del(l);
		for (;l>a[i].l;l--) insert(l-1);
		
		for (;now<a[i].time;now++) in_time(now+1);
		for (;now>a[i].time;now--) out_time(now);
		
		a[i].ans=tmp;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&col[i]);
	block=sqrt(n);
	for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
	
	char ch[2];
	int x,y;
	for (int i=1;i<=m;i++)
	{
		scanf("%s",ch);
		scanf("%d%d",&x,&y);
		if (ch[0]=='Q') a[++query_num]=(aa){x,y,time,i};
		else q[++time]=(bb){x,y,0};
	}
	sort(a+1,a+query_num+1);
	work();
	sort(a+1,a+query_num+1,cmp);
	for (int i=1;i<=query_num;i++) printf("%d\n",a[i].ans);
	return 0;
}


 做法二:

如果沒有修改就是,處理不重複的基本思路,這個顏色上一個出現位置在l之前。

對於詢問l~r,就是詢問l~r中多少pre在l之前的。

考慮差分,其實就是在1~r中多少數小於l,主席樹模板。

 

但是更改一個顏色就會出現,pre的改變。pre改變用set來維護,有更改就再套上一個樹狀數組就好。

 

注意:主席樹的更改是很暴力的,其實就是暴力增加log 個節點罷了。

 

當然基本思路還是求區間小於等於一個數的個數。

 

還有就是修改一個顏色,會影響當前點的值和他後繼的值,那麼就是取後繼和前驅,刪除插入一個數。這用set就可以解決,原先分塊寫這題,更改這個地方暴力做的,麻煩了

#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int N=11005;
const int N2=1000005;

int n,m,c[N];
//////////////////
int b[N],nn;
set<int> col[N];
set<int>::iterator it,pre,next;
//////////////////
struct Query
{
	char ch[2];
	int x,y;
}Que[N];
/////////////////
int tot,rt[N];
struct aa
{
	int lc,rc,l,r,sum;
}a[N*20*20];
void build(int &u,int l,int r)
{
	u=++tot;
	a[u].l=l,a[u].r=r;
	if (l==r) return;
	int mid=(l+r)>>1;
	build(a[u].lc,l,mid);
	build(a[u].rc,mid+1,r);
}
void updata(int old,int &now,int pos,int add)
{
	now=++tot;
	a[now]=a[old];
	a[now].sum+=add;
	if (a[old].l==a[old].r) return;
	int mid=(a[old].l+a[old].r)>>1;
	if (pos<=mid) updata(a[old].lc,a[now].lc,pos,add);
	else updata(a[old].rc,a[now].rc,pos,add);
}
int sum(int u,int t)
{
	if (t==a[u].r) return a[u].sum;
	int mid=(a[u].l+a[u].r)>>1;
	if (t<=mid) return sum(a[u].lc,t);
	return a[a[u].lc].sum+sum(a[u].rc,t);
}
///////////////////
inline int lowbit(int x){return x&(-x);}
void updata(int i,int last,int add)
{
	int v;
	for (;i<=n;i+=lowbit(i)) 
	{
		updata(rt[i],v,last,add);
		rt[i]=v;
	}
}
int query(int i,int t)
{
	int ans=0;
	for (;i;i-=lowbit(i)) ans+=sum(rt[i],t);
	return ans;
}
/////////////////
int head[N];

void work(int l,int r)
{
	printf("%d\n",query(r,l-1)-query(l-1,l-1));
}

void change(int pos,int now)
{
	now=lower_bound(b+1,b+nn+1,now)-b;
	int old=c[pos];
	
	pre=next=it=col[old].lower_bound(pos);
	pre--;next++;
	updata(pos,*pre,-1);
	if (next!=col[old].end()) updata(*next,pos,-1),updata(*next,*pre,1);
	
	col[old].erase(it);col[now].insert(pos);c[pos]=now;
	
	pre=it=next=col[now].lower_bound(pos);
	pre--;next++;
	updata(pos,*pre,1);
	if (next!=col[now].end()) updata(*next,*pre,-1),updata(*next,pos,1);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&c[i]),b[++nn]=c[i];
	for (int i=1;i<=m;i++)
	{
		scanf("%s",Que[i].ch);
		scanf("%d%d",&Que[i].x,&Que[i].y);
		if (Que[i].ch[0]=='R') b[++nn]=Que[i].y;
	}
	////
	sort(b+1,b+nn+1);
	nn=unique(b+1,b+nn+1)-b-1;
	for (int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+nn+1,c[i])-b;
	for (int i=1;i<=nn;i++) col[i].insert(0);
	////
	
	build(rt[0],0,n);
	for (int i=1;i<=n;i++) rt[i]=rt[0];
	
	for (int i=1;i<=n;i++)
	{
		updata(i,head[c[i]],1);
		head[c[i]]=i;
		col[c[i]].insert(i);
	}
	
	for (int i=1;i<=m;i++)
	{
		Query t=Que[i];
		if (t.ch[0]=='Q') work(t.x,t.y);
		else change(t.x,t.y);
	}
	return 0;
}


 

發佈了98 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章