Training record 6: data structure

Posted by LBmtb on Tue, 07 Dec 2021 01:56:33 +0100

Priority queue

poj3614

Meaning: a group of cows bask in the sun. Each cow has a limit of solar intensity, minSPA and maxSPA, but the sun is too fierce. Cows need to apply sunscreen to bask in the sun. Sunscreen can fix the solar intensity at a value. If it is smaller than minSPA, it will still burn. If it is larger than maxSPA, cows will not feel much. Each cow can apply a bottle of sunscreen at most, give the SPA value and quantity of sunscreen, and ask how many cows can enjoy the sun

Idea: it is mainly greedy. You can enumerate cows and sunscreen respectively. If you enumerate cows, it is not convenient to maintain the number of sunscreen. Therefore, you choose to enumerate sunscreen. Assuming that sunscreen is ranked from small to large by spa, which cow should be selected among the cows that meet the conditions (minspa ≤ SPA). The answer is the one with the smallest maxSPA. Because the spa value of sunscreen is getting larger and larger, the cows with larger maxSPA can be reserved for larger sunscreen.

The priority queue (small root heap) can be used to maintain maxSPA. If the top of the heap meets the conditions (maxSPA ≥ SPA), this sunscreen num-- can be used. If it does not meet the requirements, it can be discarded directly, because if the current sunscreen does not meet the requirements, the larger sunscreen behind it will not be satisfied

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<iomanip>
using namespace std;
typedef long long ll;
const long long ll_inf=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int Max=3000+5;
const int Mod=1e9;
#define _for(i,n) for(int i=0;i<n;++i)
#define _rep(i,n) for(int i=1;i<=n;++i)
//cout<<setw(8)<<fixed<<setprecision(3);
//ios::sync_with_stdio(false);
//priority_queue<int,vector<int>,greater<int> >
struct node{
	int ma,mi;
	bool operator < (const node &r)const{
		return mi<r.mi;
	}
}cow[Max];
struct node2{
	int spa,num;
	bool operator < (const node2 &r)const{
		return spa<r.spa;
	}
}sp[Max];
int c,l;
int main(){
	ios::sync_with_stdio(false);
	cin>>c>>l;
	_for(i,c) cin>>cow[i].mi>>cow[i].ma;
	_for(i,l) cin>>sp[i].spa>>sp[i].num;
	sort(sp,sp+l);
	sort(cow,cow+c);
	int ans=0,j=0;
	priority_queue<int,vector<int>,greater<int> > q;
	_for(i,l){//Enumerate each sunscreen 
		while(j<c&&cow[j].mi<=sp[i].spa){
			q.push(cow[j].ma);
			j++; 	
		}
		while(!q.empty()&&sp[i].num){
			int x=q.top();
            q.pop();
            if(x<sp[i].spa) continue;
            ans++;
            sp[i].num--;
		}
	}
	cout<<ans<<'\n';
	return 0;
}

While (J < C & & cow [J]. Mi < = SP [i]. SPA) the queue entry condition should not add cow [J]. Ma > = SP [i]. Spa. Although it seems reasonable: if the maximum value is less than spa, you don't need to join the queue, but it will lead to the direct end of the cycle and the omission of the cows behind this cow

poj2010

There are C cows in total, and N cows should be selected. Each cow has a value and cost. It is required that the total cost of N cows should be less than F. at the same time, the median value of N cows is the largest, and the median value should be output

Idea: if the ith cow is selected, N/2 cows will be selected between 1 and i and between i and c respectively, and the selection of those cows has no effect on the median. Therefore, the cows with the lowest cost can be selected, and the priority queue can be considered. However, if T is calculated only when enumerating each cow, consider preprocessing the minimum value of N/2 cows among 1 to i and i to c cows, and then query with O(n)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<iomanip>
using namespace std;
typedef long long ll;
const long long ll_inf=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int Max=100000+5;
const int Mod=1e9;
//cout<<setw(8)<<fixed<<setprecision(3);
//ios::sync_with_stdio(false);
//priority_queue<int,vector<int>,greater<int> >
#define _for(i,n) for(int i=0;i<n;++i)
#define _rep(i,n) for(int i=1;i<=n;++i)
struct node{
	int val,cos;
	bool operator < (const node &r)const{
		return val>r.val;
	}
}cow[Max];
int dp1[Max];
int dp2[Max];
int N,C,F; 
int main(){
	ios::sync_with_stdio(false);
	cin>>N>>C>>F;
	_for(i,C){
		cin>>cow[i].val>>cow[i].cos; 
	}
	if(N==1){
		if(cow[0].cos<=F)
		cout<<cow[0].val<<'\n';
		else
		cout<<"-1";
		return 0;
	}
	sort(cow,cow+C);
	int low=N/2;
	priority_queue<ll> q;
	for(int i=0;i<low;++i){
		q.push(cow[i].cos);
		dp1[low]+=cow[i].cos;
	}
	for(int i=low+1;i<C;i++){
		if(cow[i-1].cos>=q.top())
		dp1[i]=dp1[i-1];
		else
		dp1[i]=dp1[i-1]+cow[i-1].cos-q.top();
		q.pop();
		q.push(cow[i-1].cos);
	}
	while(!q.empty())
	q.pop();
	for(int i=C-1;i>C-low-1;i--){
		q.push(cow[i].cos);
		dp2[C-low-1]+=cow[i].cos;		
	}
	for(int i=C-low-2;i>=0;i--){
		if(cow[i+1].cos>=q.top())
		dp2[i]=dp2[i+1];
		else{
			dp2[i]=dp2[i+1]+cow[i+1].cos-q.top();
			q.pop();
			q.push(cow[i+1].cos);		
		}
	}
	int i,flag=0;
	for(i=N/2;i<C-N/2;i++){
		int ans=cow[i].cos;
		ans+=dp1[i];
		ans+=dp2[i];
		if(ans<=F){
			flag=1;
			break;
		}
	}
	if(flag)
	cout<<cow[i].val<<'\n';
	else
	cout<<"-1";
	return 0;
}

If the preprocessing part is too violent, T (for example, me) will also be. Here we learn the method of others. For the first N/2 cows, add up and store them in dp[N/2] (I like to start from 0), and start from N/2+1 cows. If the cost of this cow is greater than the first in the priority queue at this time (the first in the queue saves the largest in the first N/2), dp [] is directly equal to the previous dp [] (if you are bigger than the team leader, you will not be selected). On the contrary, dp[i] =dp[i-1] +cow[i-1].cos-q.top() means to replace the heap top with a small one and update the heap top. In addition, dp[i] does not include the ith cow. Remember to add the cost of the ith cow in the subsequent query.

poj2236

Meaning: give some coordinates, a distance d and some strings, either repair a coordinate or query whether the two repaired coordinates can be connected. Connecting means that the distance between the two coordinates is less than d or can be connected through one or more repaired intermediate coordinates

Idea: check the set of naked questions.

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<iomanip>
using namespace std;
typedef long long ll;
const long long ll_inf=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int Max=1000+5;
const int Mod=1e9;
//cout<<setw(8)<<fixed<<setprecision(3);
//ios::sync_with_stdio(false);
//priority_queue<int,vector<int>,greater<int> >
#define _for(i,n) for(int i=0;i<n;++i)
#define _rep(i,n) for(int i=1;i<=n;++i)
int par[Max];
int Rank[Max];
void init(int n){
	for(int i=0;i<n;i++){
		par[i]=i;
		Rank[i]=0;
	}
}
int find(int x){
	if(par[x]==x)
	return x;
	else
	return par[x]=find(par[x]);//Has been compressed 
}
void unite(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y)
	return ;
	if(Rank[x]<Rank[y]){
		par[x]=y;
	}else{
		par[y]=x;
		if(Rank[x]==Rank[y])
		Rank[x]++;	
	}
}
bool same(int x,int y){
	return find(x)==find(y);
}
struct node{
	int x,y;
}p[Max];
int n,d;
bool Can(int a,int b){
	int dis=(p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y);
	return dis<=d*d;
}
int main(){
	cin>>n>>d;
	int flag[Max]={0};
	int f=0;
	init(n);
	_for(i,n){
		cin>>p[i].x>>p[i].y;
	}
	char a;	
	int b,c;
	while(cin>>a){
		if(a=='O'){//repair 
			cin>>b;
			b--;	
			_for(i,f){
				if(Can(flag[i],b)){
					unite(flag[i],b);
					
				}			
			}
			flag[f++]=b;
		}else{
			cin>>b>>c;
			b--;
			c--;
			if(same(b,c))
			cout<<"SUCCESS\n";
			else
			cout<<"FAIL\n";
		}
	}
}

This problem is 1w milliseconds. It does not concern the synchronization stream 8000, but 3000. It is changed to scanf 1000

poj1703

Meaning: there are two gangs. Give some sentences. Either ask whether two people belong to the same gang, or give that two people are not from the same gang.

Idea: it's a question carved out of a mill with the food chain (poj1182), but it's actually a simplified version of it. Then the idea is very clear. Open the size of 2*n. The first n represents Gang A and the last n represents Gang B. Find a, B or a+n, b+n when asking, and merge a, b+n and B, a+n when giving information. At the same time, the purpose of merging is to simplify the operation, that is, merge all possibilities, so as not to find out which Gang it already belongs to.

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<iomanip>
using namespace std;
typedef long long ll;
const long long ll_inf=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int Max=1e5+5;
const int Mod=1e9;
//cout<<setw(8)<<fixed<<setprecision(3);
//ios::sync_with_stdio(false);
//priority_queue<int,vector<int>,greater<int> >
#define _for(i,n) for(int i=0;i<n;++i)
#define _rep(i,n) for(int i=1;i<=n;++i)
int par[Max*2];
int Rank[Max*2];
void init(int n){
	for(int i=0;i<n;i++){
		par[i]=i;
		Rank[i]=0;
	}
}
int find(int x){
	if(par[x]==x)
	return x;
	else
	return par[x]=find(par[x]);//Has been compressed 
}
void unite(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y)
	return ;
	if(Rank[x]<Rank[y]){
		par[x]=y;
	}else{
		par[y]=x;
		if(Rank[x]==Rank[y])
		Rank[x]++;	
	}
}
bool same(int x,int y){
	return find(x)==find(y);
}
int main(){
	int t;
	scanf("%d",&t);
	//cin>>t;
	while(t--){
		int n,m;
		scanf("%d %d",&n,&m);
		//cin>>n>>m;
		init(2*n);
		_for(i,m){
			char a;
			int x,y;
			getchar();
			scanf("%c %d %d", &a, &x, &y);
			//cin>>a;
			if(a=='A'){
				if(same(x,y)||same(x+n,y+n)){
					cout<<"In the same gang.\n";
				}else if(same(x+n,y)||same(x,y+n)){
					cout<<"In different gangs.\n";
				}else{
					cout<<"Not sure yet.\n";
				}
			}else{
				unite(x,y+n);
				unite(x+n,y);
			}
		}
	}
}

In addition, note that the two arrays used in the search set should be opened twice, otherwise you'll have to eat it

Topics: C++