5.14测试

前言

今天测试,又被一众大佬摁在地上摩擦……只有150……

题目

1. 查询 (query)

题意:区间查询值为X的数的个数。

由于忘记了vector的二分,只好用分块来做,但是卡着时限……

#include<bits/stdc++.h>
using namespace std;

int n,q,l,r,x,a;
vector<int> pos[200005];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
	{
        scanf("%d",&a);
        pos[a].push_back(i);
    }
    scanf("%d",&q);
    while(q--)
	{
        scanf("%d%d%d",&l,&r,&x);
        int p1=lower_bound(pos[x].begin(),pos[x].end(),l)-pos[x].begin();//第一个大等于的位置
        int p2=upper_bound(pos[x].begin(),pos[x].end(),r)-pos[x].begin(); //第一个大于的位置
        printf("%d\n",p2-p1); 
    }
    return 0;
}

2.画画(paint)

题意:给一个矩形,每次选一种颜色填一个矩形,每种颜色只有一次。询问有多少种颜色可以是最开始涂的。

思路:把矩形压缩后处理,不然要超空间。处理出最小和最大的横纵坐标,遍历该矩形内,如有其他颜色就记录。注意跳开已经统计的颜色。

#include<bits/stdc++.h>
#define M 1000010
#define p(a, b) (a * mm + b - mm)
using namespace std;
int x_min[M],x_max[M],y_min[M],y_max[M],used[M],a[M],ans,n,m,K,fl,nxt[M],pre[M],vis[M],mm,u;
int find(int x){
	if(!vis[x]) return x;
	return  nxt[x]=find(nxt[x]);
}
int main(){
	fl=0;
	cin>>n>>m>>K;
	memset(x_min,0x3f,sizeof (x_min));
	memset(y_min,0x3f,sizeof (y_min));
	memset(x_max, 0, sizeof(x_max));
	memset(y_max, 0, sizeof(y_max));
	memset(used, 0, sizeof(used));
	mm=max(n,m);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++){
			if(n > m) u = p(j, i);
			else u = p(i, j);
			scanf("%d", &a[u]);
		}
	if(n > m)swap(n, m);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++){
			u = p(i, j);
			nxt[u] = p(i, j + 1);
			pre[u] = p(i, j - 1);
			if(x_max[a[u]] == 0 && a[u])fl++;
			if(i < x_min[a[u]])x_min[a[u]] = i;
			if(i > x_max[a[u]])x_max[a[u]] = i;
			if(j < y_min[a[u]])y_min[a[u]] = j;
			if(j > y_max[a[u]])y_max[a[u]] = j;
		}
	for(int i=1;i<=K;i++){
		if(x_min[i]<=x_max[i]){
			for(int j=x_min[i];j<=x_max[i];j++){
				for(int k=y_min[i];k<=y_max[i];k=find(nxt[k])){
					if(a[p(j, k)]!=i){
						used[a[p(j, k)]]=1;
						vis[p(j, k)]=1;
						nxt[pre[p(j, k)]]=nxt[p(j ,k)];
						pre[nxt[p(j, k)]]=pre[p(j, k)];
					}
				}
			}
		}
	}
	for(int i=1;i<=K;i++)
		if(!used[i]) ans++;
	if(ans==K&&fl==1&&ans>1) ans--;
	if(fl) cout<<ans<<endl;
	else cout<<0<<endl;
	return 0;
}

3.数列(seq)

题意:

第一行三个整数\(𝑛, 𝑚, 𝑝\)表示数列长度\(𝑛\),询问个数\(𝑚\)和模数\(𝑝\)

\(𝑚\)行,每行三个整数\(𝑙, 𝑟, 𝑘\),表示小B回答区间\([𝑙, 𝑟]\)中所有数的和对\(𝑝\)取模结果为\(𝑘\)

输出最大的\(𝑋\),满足小B的前\(𝑋\)次回答中不存在矛盾。

思路:

\(S_i-S_j \equiv k (\mod p) \to S_i \equiv S_j+k (\mod p)\)

\(S_r-S_{l-1} \equiv k(\mod p)\)

所以,采用带权并查集,维护每个点到父亲的K值,每次加边并判断。

#include<bits/stdc++.h>
#define N 1000010
using namespace std;
map<int,int>dad,h;
int n,m,l,r,X,Y,i,t,k,p;
char s1[110];
int find(int x){
	if(!dad[x]) return x;
	int t=find(dad[x]);
	h[x]=(h[x]+h[dad[x]])%p;//累加边长
	return dad[x]=t;
}
int main(){
	cin>>n>>m>>p;
	for(i=1;i<=m;i++){
		cin>>l>>r>>k;
		l--;
		X=find(l);
		Y=find(r);
		t=(h[r]-h[l]+p)%p;//判重
		if(X!=Y){//连边
			dad[X]=Y;
			h[X]=(t-k+p)%p;
		}else if(t!=k) break;
	}
	cout<<i-1<<endl;
	return 0;
}
posted @ 2022-05-14 16:33  SSZX_loser_lcy  阅读(30)  评论(0编辑  收藏  举报