【数据结构】水题集合

(好不容易从大神那里拿来的复习巩固的数据结构题目,,然后就,,,看到这些题,,,两个小时六道,,然后就大模拟赛了,,所以好几天了,这样的话,我就一不小心就断更了,,)
(都是UVA的题,,,ACM制的害我一顿好调的,,)
这篇博客可能有点长,总共十道题,从初级数据结构到高级数据结构的事情。

题目1:

题目链接:
UVA11995 I Can Guess the Data Structure!
题解:
初级数据结构的大集合,,,栈,队列,优先队列(堆),看到这个题就直接想都没有想就直接没有用STL,直接手写栈,手写队列,最重要的是手写堆,,,然后就是长达一个多小时的调,我真的服了我自己了,然后我就才写的STL,,手写堆真的,,,不说了。

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=1100;
stack<int>S;
queue<int>Q;
 priority_queue<int,vector<int>,less<int> > P;
int n,f,a[sea],ss[sea];
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		stack<int>S; queue<int>Q;
        priority_queue<int,vector<int>,less<int> > P;
		int stt=1,quee=1,prquee=1;
		for(int i=1;i<=n;i++)
		{
			int s=read(),x=read();
			if(s==1) {S.push(x);Q.push(x);P.push(x);}
			else
			{
				if(!Q.empty())
				{
					if(S.top()!=x) stt=0;
					if(Q.front()!=x) quee=0;
					if(P.top()!=x) prquee=0;
					Q.pop(); S.pop(); P.pop();
				}
				else stt=0,quee=0,prquee=0;
			}
		}
		int f=stt+quee+prquee;
		if(f>=2) {puts("not sure");continue;} 
		if(!f) {puts("impossible");continue;}
		if(stt) {puts("stack");continue;}
		if(quee) {puts("queue");continue;}
		if(prquee) {puts("priority queue");continue;}
	}
	return 0;
}

题目二:

题目链接:
UVA11991 Easy Problem from Rujia Liu?
题解:
由于之前我都是用的开桶,所以就没有很用过map,就是光知道map是logn的,,写了这题就算是再学学吧,刚开始就是在想分块的做法,毕竟在写区间众数的时候比那就想到了分块,但是突然发现分块其实不可写,就想着开个桶估计就可以了吧,但是,,,,桶的复杂度很难保证(不知道为什么就又想到了类似于桶的权值线段树,,,),一段时间的一本正经的胡思乱想之后,,,才看到了map<vector<>>的写法,表示真的没想到,,,

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
map<int,vector<int> >mm;//就当是练练map的写法了
int n,m;
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		mm.clear();
		for(int i=0;i<n;i++) 
		{
			int x=read();
			if(!mm.count(x)) mm[x]=vector<int>();
			mm[x].push_back(i+1);
		}
		for(int i=1;i<=m;i++)
		{
			int x=read(),y=read();
			if(!mm.count(y)||mm[y].size()<x) puts("0");
			else printf("%d\n",mm[y][x-1]);
		}
	}
	return 0;
}

题目三:

题目链接:
UVA1329 Corporative Network
题解:
很显然的并查集,,,无话可说。

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=200100;
int n,T,fa[sea],dis[sea];
int get(int x)
{
	if(x!=fa[x]) 
	{
		int k=get(fa[x]);
		dis[x]+=dis[fa[x]];
		return fa[x]=k;
	}
	return x;
}
int main()
{
	T=read(); 
	while(T--)
	{
		n=read(); char s;
		for(int i=1;i<=n;i++) fa[i]=i,dis[i]=0;
		while(cin>>s&&s!='O')
		{
			if(s=='E')
			{
				int x=read(); get(x);
				printf("%d\n",dis[x]);
			}
			else
			{
				int x=read(),y=read();fa[x]=y; 
				dis[x]=abs(x-y);
				dis[x]%=1000;
			}
		}
	}
	return 0;
} 

题目四:

题目链接:
UVA1203 Argus
题解:
一道赤裸裸的优先队列(堆),,也是无话可说,,,

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea= 1e4+7;
struct hit
{
	int time,id,x;
	bool operator<(const hit&a)const {return x>a.x||(x==a.x&&id>a.id);}
};
priority_queue<hit>Q;
int n;string s;
int main()
{
	while(cin>>s&&s[0]!='#')
	{
		hit t; t.id=read();t.time=read();
		t.x=t.time; Q.push(t);
	}
	n=read();
	for(int i=1;i<=n;i++)
	{
		hit a=Q.top(); Q.pop();
		printf("%d\n",a.id);
		a.x+=a.time; Q.push(a); 
	}
	return 0;
}

题目五:

题目链接:
UVA1160 X-Plosives
题解:
并查集,,就不说了,(这题,,水到突然连代码都不想放了,,)

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=1e5+7;
int fa[sea],ans;
int get(int x){if(x==fa[x]) return x;else return fa[x]=get(fa[x]);}
int main()
{
	int x,y;
	for(int i=1;i<=sea;i++) fa[i]=i;ans=0;
	while(~scanf("%d",&x))
	{
		if(x!=-1)
		{
			y=read();
			int a=get(x),b=get(y);
			if(a!=b) fa[a]=b;
			else ans++;
		}
		else 
		{
			printf("%d\n",ans);
			for(int i=1;i<=sea;i++) fa[i]=i; 
			ans=0; continue;
		}
	}
	return 0;
}

题目六:

题目链接:
UVA1428 Ping pong
题解:
这个题可以写线段树的,树状数组也是可以的,但是树状数组代码短啊,但是我还是又一次好好看了看树状数组,毕竟我的树状数组,真的,,好菜,,,,所以就写写就当练练了。

代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=1e5+7;
int T,n,a[sea],c[sea],d[sea],f[sea];
int lowbit(int x){return x&-x;}
void add(int x,int y){while(x<=sea){f[x]+=y,x+=lowbit(x);}}
int sum(int x){int s=0;while(x>0){s+=f[x],x-=lowbit(x);}return s;}
int main()
{
	T=read();
	while(T--)
	{
		memset(a,0,sizeof(a));
        memset(c,0,sizeof(c));
        memset(d,0,sizeof(d));
        memset(f,0,sizeof(f));
		n=read();
		for(int i=1;i<=n;i++)a[i]=read();
		add(a[1],1);
		for(int i=2;i<n;i++)
		{
			c[i]=sum(a[i]-1);
			add(a[i],1);
		}
		memset(f,0,sizeof(f));
		add(a[n],1);
		for(int i=n-1;i>=2;i--)
		{
			d[i]=sum(a[i]-1);
			add(a[i],1);
		} 
		LL ans=0;
		for(int i=1;i<=n;i++) ans+=c[i]*(n-i-d[i])+(i-1-c[i])*d[i];
		printf("%lld\n",ans);
	}
	return 0;
}

题目七:

题目链接:
UVA11997 K Smallest Sums
题解:
这题,写的时候读了好几遍题目,搞了快半个小时才读懂,,我都,,了,,还是放一下题面吧,要不然还是想不起来题,重看还浪费时间,,,:

给定一个 k ∗ k k*k kk的一个矩阵,如果让你在每一行取出一个数,再将每一行取出的数相加,那么总共可以得到 k k k^k kk种相加方法,现在让你求出这 k k k^k kk个结果中最小的k个结果。

这其实是个 类似于递推的东西,也可以直接称为递推出来的,结论是:f[k]+a[1]是第k个最小的和,所以就只用处理一下a[1]的结果就行了,然后就会得到一个这n2的有序表然后就我们维护一个可能成为ans的序列,每次取这个序列中最小(这就可以写一个优先队列了)。同时不妨设这个值为ai+bj,那么我们将ai+bj+1压入序列,因为它可能成为合法的ans,这就是用堆来维护一个可以进行修改操作的答案,,,这想法,,太妙了。

初始化上,因为ai+b1可能成为合法的ans,我们将这k个全部压入队列中。

这位大佬的严格证明比较详细。

代码:

#include<bits/stdc++.h>
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
using namespace std;
const int sea=1010;
struct hit
{
	int id,val;
	hit (int a=0,int b=0){val=a,id=b;}
	bool operator < (const hit &a) const {return val>a.val||(val==a.val&&id<a.id);} 
};
int n,a[sea],ans[sea];
priority_queue<hit>Q;  
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		memset(ans,0,sizeof(ans));
		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++) ans[i]=read();
		for(int i=2;i<=n;i++)
		{
			for(int j=1;j<=n;j++) a[j]=read();
			sort(a+1,a+1+n); while(!Q.empty()) Q.pop();
			for(int j=1;j<=n;j++) Q.push(hit(a[1]+ans[j],1)); 
			for(int j=1;j<=n;j++)
			{
				hit tt=Q.top(); Q.pop(); ans[j]=tt.val;
				if(tt.id<n) Q.push(hit(tt.val-a[tt.id]+a[tt.id+1],tt.id+1)); 
			}
		}
		for(int i=1;i<n;++i) printf("%d ",ans[i]);printf("%d\n",ans[n]);	
	}
	return 0;
}

题目八:

题目链接:
UVA11992 Fast Matrix Operations
题解:
二十颗线段树,,,我竟然码到130行+,,,这题啊,就是练你的线段树的码力,,,都是比较普通的操作,但是就是比较多而且比较复杂,但是值得反复写写练习线段树的板子,,,
(可是就是不是太好调,,,)

代码:

#include<bits/stdc++.h>
#define lk ls[k]
#define rk rs[k]
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=1e7+7;
const int ocean=0x3fffffff;
struct hit{int sum,max,min,ladd,lset;}tr[sea*4];
int q,n,m,seg,tid[sea],ls[sea],rs[sea];
void down(int k,int l,int r)
{
	int mid=(l+r)/2;
	if(tr[k].lset)
	{
		tr[lk].lset=tr[k].lset; tr[rk].lset=tr[k].lset;
		tr[lk].max=tr[k].lset; tr[rk].max=tr[k].lset;
		tr[lk].min=tr[k].lset; tr[rk].min=tr[k].lset;
		tr[lk].sum=tr[k].lset*(mid-l+1),tr[rk].sum=tr[k].lset*(r-mid);
		tr[lk].ladd=tr[rk].ladd=tr[k].lset=0;
	}
	if(tr[k].ladd)
	{
		tr[lk].ladd+=tr[k].ladd,tr[rk].ladd+=tr[k].ladd;
		tr[lk].max+=tr[k].ladd,tr[rk].max+=tr[k].ladd;
		tr[lk].min+=tr[k].ladd,tr[rk].min+=tr[k].ladd;
		tr[lk].sum+=tr[k].ladd*(mid-l+1),tr[rk].sum+=tr[k].ladd*(r-mid);
		tr[k].ladd=0;
	}
}
void up(int k)
{
	tr[k].sum=tr[lk].sum+tr[rk].sum;
	tr[k].max=max(tr[lk].max,tr[rk].max);
	tr[k].min=min(tr[lk].min,tr[rk].min);
}
int build(int l,int r)
{
	int k=++seg; tr[k].ladd=tr[k].lset=0;
	if(l==r){tr[k].sum=tr[k].min=tr[k].max=0;lk=rk=0;return k;}
	int mid=(l+r)/2;
	lk=build(l,mid); rk=build(mid+1,r);	up(k);
	return k;
}
void alter_add(int k,int l,int r,int x,int y,int z)
{
	if(l>=x&&y>=r)
	{
		tr[k].max+=z,tr[k].min+=z;
		tr[k].sum+=(r-l+1)*z;
		tr[k].ladd+=z;
		return ;
	}
	down(k,l,r); int mid=(l+r)/2;
	if(x<=mid) alter_add(lk,l,mid,x,y,z);
	if(y>mid) alter_add(rk,mid+1,r,x,y,z);
	up(k);
}
void alter_set(int k,int l,int r,int x,int y,int z)
{
	if(l>=x&&y>=r)
	{
		tr[k].max=z; tr[k].min=z;
		tr[k].lset=z; tr[k].ladd=0;
		tr[k].sum=z*(r-l+1);
		return ;
	}
	down(k,l,r); int mid=(l+r)/2;
	if(x<=mid) alter_set(lk,l,mid,x,y,z);
	if(y>mid) alter_set(rk,mid+1,r,x,y,z);
	up(k);
}
int ask_sum(int k,int l,int r,int x,int y) 
{
	if(l>=x&&y>=r) 	return tr[k].sum;
	down(k,l,r); int mid=(l+r)/2; 
	int ans=0;
	if(x<=mid) ans+=ask_sum(lk,l,mid,x,y);
	if(y>mid) ans+=ask_sum(rk,mid+1,r,x,y);
	return ans;
}
int ask_max(int k,int l,int r,int x,int y)
{
	if(l>=x&&y>=r) return tr[k].max;
	down(k,l,r); int mid=(l+r)/2;
	int ans=-ocean;
	if(x<=mid) ans=max(ans,ask_max(lk,l,mid,x,y));
	if(y>mid) ans=max(ans,ask_max(rk,mid+1,r,x,y));
	return ans;
}
int ask_min(int k,int l,int r,int x,int y)
{
	if(l>=x&&y>=r) return tr[k].min;
	down(k,l,r); int mid=(l+r)/2;
	int ans=ocean;
	if(x<=mid) ans=min(ans,ask_min(lk,l,mid,x,y));
	if(y>mid) ans=min(ans,ask_min(rk,mid+1,r,x,y));
	return ans;
}
int main()
{
	while(~scanf("%d%d%d",&n,&m,&q))
	{
		memset(tr,0,sizeof(tr));
		for(int i=1;i<=n;i++) tid[i]=build(1,m);
		for(int i=1;i<=q;i++)
		{
			int s=read(),x1=read(),y1=read(),x2=read(),y2=read(),z;
			if(s==1){z=read(); for(int j=x1;j<=x2;j++) alter_add(tid[j],1,m,y1,y2,z);}
			if(s==2){z=read(); for(int j=x1;j<=x2;j++) alter_set(tid[j],1,m,y1,y2,z);}
			if(s==3)
			{
				int summ=0,maxn=-ocean,minn=ocean;
				for(int j=x1;j<=x2;j++) 
				{
					summ+=ask_sum(tid[j],1,m,y1,y2);
					maxn=max(maxn,ask_max(tid[j],1,m,y1,y2));
					minn=min(minn,ask_min(tid[j],1,m,y1,y2));
				}
				printf("%d %d %d\n",summ,minn,maxn);
			}
		}
	}
	return 0;
} 

题目九:

题目链接:
UVA11235 Frequent values
(双倍经验SP1684 FREQUENT - Frequent values)
题解:
其实我刚拿到这些题之后就是先看到的这个题,然后就在没有看清题的情况下想到了分块的区间众数,然后就再次不暴毙了,,,没有注意到那个连续出现,又一次暴毙,,,看了看题解,发现是RMQ,然后就又孤陋寡闻了,,没学过RMQ,,怎么办,,,就学学呗,还能怎么办,,,,

这个题就其实连续出现就是对于数组上进行一个离散化处理就好了,,(这么说其实还是能用分块来写的,,但是RMQ代码短啊,而且,跑的还比分块快,,)

RMQ,一种建立在倍增上的数据结构的算法,是专门用来解决区间最值查询问题,博客推荐。(今天有点懒了,,,,不想具体写了,,有时间回来补,,,一定会补的!!)

代码:

#include<bits/stdc++.h>
#define D double
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=1e5+7;
int n,m,a[sea],b[sea],f[sea][20];
void RMQ()
{
	for(int i=1;i<=n;i++) f[i][0]=b[i];
	int k=log((D)(n+1))/log(2.0);
	for(int j=1;j<=k;j++) for(int i=1;i+(1<<j)-1<=n;i++)
	f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 
}
int ask(int x,int y)
{
	if(y<x) return 0;
	int k=log((D)(y-x+1))/log(2.0);
	return max(f[x][k],f[y-(1<<k)+1][k]);
}
int main()
{
	while(scanf("%d",&n)!=EOF&&n)
	{
		m=read(); b[1]=1;
		for(int i=1;i<=n;i++) a[i]=read();	
		for(int i=1;i<=n;i++)
		{
			if(i>1&&a[i]==a[i-1]) b[i]=b[i-1]+1;
			else b[i]=1;
		}
		RMQ();
		for(int i=1;i<=m;i++)
		{
			int x=read(),y=read(),z;z=x;
			while(z<=y&&a[z]==a[z-1]) z++;
			printf("%d\n",max(z-x,ask(z,y)));
		}
	}
	return 0;
}

题目十:

题目链接:UVA1400 “Ray, Pass me the dishes!”
题解:最大子段和,,,

总结:

(本来说是十道题的还有一道还没有写,最大子段和,是和线段树直接合并,已经放到任务计划了,有时间肯定补,,,)

这样子其实就是把noip之前的几乎所有的要考的数据结构写了一遍吧,表示又复习了一下比较容易忽略的知识点,但是每一道题都没有那么深,就是板子似的东西,对于noip其实是需要一些比较巧妙地思想运用比较普遍的算法写出比较精简的代码的题,这一套题其实总体下来就是比较板子的,,所以总让我想写分块,,,分块这个梗是过不去了,,,,

小插曲:

在昨天刘神的一道线段树的考验下,,我发现,,线段树,,有白学了,,而且还是刚从海亮回来老师讲过的题,完了,可能海亮也白去了,,,。回来好好学学线段树。

Continue……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值