2017 9 6 noip模拟赛T3

懒得搬题面QAQ

看到这题一眼莫队hhhhhh

但是数据离散化得用hash

因为莫队还得支持插入和删除

然后还得支持重复利用cnt

所以我打了1800K+接近2hQAQ

好菜啊QAQ

主要是hash比较不熟。。

莫队真是好东西

不过其实这道题很多都可以写

树套树。。(忘记线段树套平衡树怎么写了QAQ)

还有O(N)的做法(可以看成是扫描线吧QAQ)

把询问的l和r拆开

然后sum[r]-sum[l-1]就可以了

还是支持莫队QAQ

做法1:莫队

1e5的数据时间0.7s左右

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
const int N=1e5+100,mod=1e7+19;
struct node
{
	int l,r,x,order;
}e[N];
struct edgt
{
	int next,val;
	void clear()
	{
		next=0,val=0;
	}
}f[N];
int m;
int first[mod+20],cnt=0;
bool ans[N];
int vi[N];
int pos[N];
int qu[N+10];
int head=1,tail=1;
int getnum()
{
	int d=qu[head++];if(head==N)	head=0;
	return d;
}
void add(int x)
{
	qu[tail++]=x;if(tail==N)	tail=0;
}
void gethash(int x)
{
	int end=x%mod;
	int tot=getnum();
	f[tot].next=first[end];first[end]=tot;f[tot].val=x;
}
void del(int x)
{
	int end=x%mod;
	int pre=0;
	int k=first[end];
	pre=k;
	if(f[k].val==x)	
	{
		first[end]=f[k].next,f[k].clear(),add(k);
		return;
	}
	k=f[k].next;
	for(;k;k=f[k].next)
	{
		if(f[k].val==x)	f[pre].next=f[k].next,f[k].clear(),add(k),
		pre=k;
	}
}
bool find(int x)
{
	int end=x%mod;
	bool flag=0;
	for(int k=first[end];k&&!flag;k=f[k].next)
	if(f[k].val==x)	flag=1;
	return flag;
}
bool cmp(node a,node b)
{
	if(pos[a.l]==pos[b.l])	return a.r<b.r;
	return a.l<b.l;
}
void work()
{
	for(int l=1,r=0,i=1;i<=m;i++)
	{
		while(r<e[i].r)	r++,gethash(vi[r]);
		while(r>e[i].r)	del(vi[r]),r--;
		while(l<e[i].l)	del(vi[l]),l++;
		while(l>e[i].l)	l--,gethash(vi[l]);
		ans[e[i].order]=find(e[i].x);
	}
}
int main()
{
	freopen("statistic.in","r",stdin);
	freopen("statistic.out","w",stdout);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)	scanf("%d",&vi[i]);
	scanf("%d",&m);
	for(int i=1;i<=m;i++)	scanf("%d %d %d",&e[i].l,&e[i].r,&e[i].x),e[i].order=i;
	
	int sqr=sqrt(n);
	for(int i=1;i<=n;i++)	pos[i]=(i-1)/sqr+1;
	std::sort(e+1,e+1+m,cmp);
	for(int i=1;i<=n;i++)	add(i);
	work();
	for(int i=1;i<=m;i++)	printf("%d",ans[i]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

做法二:nlognlogn

线段树套平衡树

时间:1.1s左右

#include<cstdio>
#include<cstring>
#include<cstdlib>
const int N=1e5+7;
int size;
struct node
{
	int size,w,v,rnd,c[2];
}tr[N*20];
#define lson tr[k].c[0]
#define rson tr[k].c[1]
int rott[4*N];
int a[N];
int sum;
void update(int k)	
{
	tr[k].size=tr[lson].size+tr[rson].size+tr[k].w;
}
void rturn(int &k)
{
	int t=tr[k].c[0];tr[k].c[0]=tr[t].c[1];tr[t].c[1]=k;
	tr[t].size=tr[k].size;update(k);k=t;
}
void lturn(int &k)
{
	int t=tr[k].c[1];tr[k].c[1]=tr[t].c[0];tr[t].c[0]=k;
	tr[t].size=tr[k].size;update(k);k=t;
}
void insert(int &k,int num)
{
	if(!k)	
	{
		k=++size;	tr[k].size=tr[k].w=1;tr[k].rnd=rand();tr[k].v=num;
		return;
	}
	tr[k].size++;
	if(num==tr[k].v)	tr[k].w++;
	else if(num<tr[k].v)
	{
		insert(lson,num);if(tr[lson].rnd<tr[k].rnd)	rturn(k);
	}
	else
	{
		insert(rson,num);if(tr[rson].rnd<tr[k].rnd)	lturn(k);
	}
}
void build(int ro,int l,int r,int num,int x)
{
	insert(rott[ro],num);
	if(l==r)	return;
	int mid=(l+r)>>1;
	if(x<=mid)	build(ro<<1,l,mid,num,x);
	else build(ro<<1|1,mid+1,r,num,x);
}
int check(int k,int num)
{
	if(sum>0)return 0;
	if(!k)	return 0;
	if(num==tr[k].v)	return tr[k].w;
	else if(num<tr[k].v)	return check(lson,num);
	else return check(rson,num);
}
void query(int ro,int l,int r,int x,int y,int num)
{
	if(sum>0)	return;
	if(x<=l&&r<=y)
	{
		sum+=check(rott[ro],num);
		return;
	}	
	int mid=(l+r)>>1;
	if(x<=mid)	query(ro<<1,l,mid,x,y,num);
	if(y>mid)	query(ro<<1^1,mid+1,r,x,y,num);
}
int main()
{
	freopen("statistic.in","r",stdin);
	freopen("statistic.out","w",stdout);
	srand(5);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)build(1,1,n,a[i],i);
	int m;
	int u,v,q;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		sum=0;
		scanf("%d %d %d",&u,&v,&q),query(1,1,n,u,v,q);
		printf("%d",sum>0?1:0);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

做法3:O(N)

把询问的端点放在1.....n上

然后扫的时候处理一下就行了

时间:0.05s左右

#include<cstdio>
#include<cstring>
const int N=1e5+7;
struct node
{
	int tag,x,next,order;
}e[2*N];
struct edgt
{
	int x,next;
}f[N];
const int mod=1e7+19;
int first[mod+52],last[mod+52];
int cnt;
void add(int u,int x,int order,int tag)
{
	e[++cnt]=(node){tag,x,first[u],order};first[u]=cnt;
}
int tot;
int read()
{
	int ans=0;char t=getchar();
	while(t<'0'||t>'9')	t=getchar();
	while(t>='0'&&t<='9')	ans=ans*10+t-'0',t=getchar();
	return ans;
}
int hash(int x)
{
	int end=x%mod;
	for(int k=last[end];k;k=f[k].next)		if(f[k].x==x)	return k;
	f[++tot]=(edgt){x,last[end]};last[end]=tot;
	return tot;
}
int sum[N],ans[N],a[N];
int find(int x)
{
	int end=x%mod;
	for(int k=last[end];k;k=f[k].next)		if(f[k].x==x)	return k;
	return 0;
}
char pu[N];
int main()
{
	freopen("statistic.in","r",stdin);
	freopen("statistic.out","w",stdout);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)	a[i]=read();
	int m;
	scanf("%d",&m);
	int u,v,q;
	for(int i=1;i<=m;i++)
	{
		u=read(),v=read(),q=read();
		add(u-1,q,i,-1);
		add(v,q,i,1);		
	}
	
	for(int i=1;i<=n;i++)	
	{
		int kkk=hash(a[i]);
		sum[kkk]++;
		for(int k=first[i];k;k=e[k].next)	
		{
			int ttt=find(e[k].x);
			ans[e[k].order]+=e[k].tag*sum[ttt];
		}
	}
	for(int i=1;i<=m;i++)	pu[i]=(ans[i]>0?1:0)+'0';
	printf("%s",pu+1);
	fclose(stdin);
	fclose(stdout);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值