清华数据结构(上) PA1 & PA2

范围查询

清华OJ不允许用stl,先写一个快排将数组排序。然后二分出<= y的秩最大的数,再二分出>= x的秩最小的数。

#include 
using namespace std;
const int N = 5*1e5+10;
int a[N], m, n;
int l, r, mid, x, y, rt;

void quick_sort(int l, int r){
     
	if(l >= r) return;
	int i = l-1, j = r+1, x = a[l+r>>1];
	while(i < j){
     
		while(a[++i] < x);
		while(a[--j] > x);
		if(i < j) swap(a[i], a[j]);
	}
	quick_sort(l, j), quick_sort(j+1, r);
}

int main(){
     
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; i ++){
     
		scanf("%d", &a[i]);
	}
	quick_sort(0, n-1);
	while(m --){
     
		scanf("%d %d", &x, &y);
		l = 0, r = n-1;
		while(l < r){
     
			mid = l + r + 1>> 1;
			if(a[mid] <= y) l = mid;
			else r = mid-1;
		}
		if(a[r] <= y) rt = r;
		else {
     
			puts("0");
			continue;
		}
		
		l = 0, r = rt;
		while(l < r){
     
			mid = l + r >> 1;
			if(a[mid] >= x) r = mid;
			else l = mid + 1;
		}
		if(a[l] >= x) printf("%d\n", rt-l+1);
		else puts("0");
	}
	return 0;
} 

祖玛

向量模拟竟然也能过,这题应该是想让大家实现双向连表的。

#include 
#include 
const int N = 2e4+10;
int n;
char str[N];
char tmp[N];
 
char* zuma_delete(char *ss, int pos){
     
	int len = strlen(ss);
	int front, back;
	front = back = pos;
	char c = ss[pos];
	int count = 1;
 
	while (--front >= 0 && ss[front] == c) count++;
	while (++back < len && ss[back] == c) count++;
		
	if (count >= 3){
     
		strcpy(tmp, ss + back);
		strcpy(ss + front + 1, tmp);
		return zuma_delete(ss, front);
	}
	else return ss;
}

void insert(int pos, char c){
     
	strcpy(tmp, str + pos);
	str[pos] = c;
	strcpy(str + pos + 1, tmp);
}
 
int main(){
     	
	fgets(str, N, stdin);
	str[strlen(str)-1] = '\0';
	scanf("%d", &n);
 
	while (n--){
     
		int pos;
		char c;
 
		scanf("%d %c", &pos, &c);
		insert(pos, c);
		
		char *p = zuma_delete(str, pos);
		if (strlen(p) == 0) puts("-");
		else printf("%s\n", p);
	}

	return 0;
}

灯塔

归并排序算逆序对

#include
#include
#include
using namespace std;
const int N = 4e6+10;

int n, x, y;
typedef long long LL;
LL ans;

struct Node{
     
	int x, y;
}alls[N], tmp[N];

void quick_sort(int l, int r){
     
	if(l >= r) return ;
	int i = l-1, j = r+1, p = alls[l+r>>1].x;
	while(i < j){
     
		while(alls[++ i].x < p) ;
		while(alls[-- j].x > p) ;
		if(i < j) swap(alls[i], alls[j]);
	}
	quick_sort(l, j), quick_sort(j+1, r);
}

void merge_sort(int l, int r){
     
	if(l >= r) return ;
	int mid = l + r >> 1;
	merge_sort(l, mid), merge_sort(mid+1, r);
	int i = l, j = mid+1, k = l;
	while(i <= mid && j <= r){
     
		if(alls[i].y < alls[j].y) ans += r-j+1, tmp[k++].y = alls[i++].y;
		else tmp[k++].y = alls[j++].y;
	}
	while(i <= mid) tmp[k++].y = alls[i++].y;
	while(j <= r) tmp[k++].y = alls[j++].y;
	for(int i = l; i <= r; i ++) alls[i].y = tmp[i].y;
//	for(int i = l; i <= r; i ++) {
     
//		alls[i].y = tmp[i].y;
//		printf("%d ", alls[i].y);
//	}
//	puts("");
}

int main(){
     
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d %d", &alls[i].x, &alls[i].y);
	quick_sort(0, n-1);
	//for(int i = 0; i < n; i ++) printf("%d %d\n", alls[i].x, alls[i].y); 
	//puts("");
	merge_sort(0, n-1);
	//for(int i = 0; i < n; i ++) printf("%d ", alls[i].y); 
	//puts("");
	printf("%lld", ans);
	return 0;
}

列车调度

判断一个序列是否是栈混洗。

#include
const int N = 1600005;
int a[N];

int main(){
     
	int m, n;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	int stk[m], tt = -1, j = 1;
	for(int i = 1; i <= n; i ++){
     
		stk[++ tt] = i;
		if(tt >= m) break;
		while(tt >= 0 && stk[tt] == a[j]) -- tt, j ++; 
	}
	if(tt > 0) puts("No");
	else{
     
		tt = -1, j = 1;
		for(int i = 1; i <= n; i ++){
     
			stk[++ tt] = i;
			puts("push");
			while(tt >= 0 && stk[tt] == a[j]) {
     
				-- tt, j ++; 
				puts("pop");
			}
		}
	} 
	return 0;
}

真二叉树重构

前序和后序可唯一确定一棵真二叉树。

#include 
using namespace std;

const int N = 4e6 + 5;
int pre[N], post[N], in[N];
int pos[N], n;

struct TreeNode{
     
	int val;
	TreeNode* left, *right;
	TreeNode(int v): val(v), left(nullptr), right(nullptr){
     }
};


TreeNode* dfs(int l1, int r1, int l2, int r2){
     
	if(l1 > r1) return NULL;
	auto root = new TreeNode(pre[l1]);
	if(l1 == r1) return root;
	int k = pos[pre[l1+1]];
	root->left = dfs(l1+1, l1+1+k-l2, l2, k);
	root->right = dfs(l1+2+k-l2, r1, k+1, r2-1);
	return root;
}

void inorder(TreeNode* root){
     
	if(!root) return ;
	inorder(root->left);
	printf("%d ", root->val);
	inorder(root->right);
}

int main(){
     
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &pre[i]);
	for(int i = 0; i < n; i ++)
		scanf("%d", &post[i]), pos[post[i]] = i;

	auto root = dfs(0, n-1, 0, n-1);
	inorder(root);
	return 0;
}

旅行商

按照拓扑顺序遍历一个有向图,当一个顶点入队时,必然走过了所有能到达这个顶点的路径,从中选取最长的一条。

#include 
#include 
const int N = 1e6+5;
int h[N], e[N], ne[N], idx;
int d[N], num[N];
int q[N], hh, tt;
int x, y, n, m;

void add(int x, int y){
     
	e[idx] = y;
	ne[idx] = h[x];
	h[x] = idx ++;
	d[y] ++;
}

int topsort(){
     
	for(int i = 1; i <= n; i ++)
		if(!d[i]) q[tt++] = i, num[i] = 1;
	while(hh < tt){
     
		int t = q[hh++];
		for(int i = h[t]; i != -1; i = ne[i]){
     
			int j = e[i];
			num[j] = num[j] > num[t]+1 ? num[j] : num[t] + 1;
			if(-- d[j] == 0) q[tt++] = j;
		}
	}
}

int main(){
     
	memset(h, -1, sizeof h);
	scanf("%d %d", &n, &m);
	for(int i = 0; i < m; i ++){
     
		scanf("%d %d", &x, &y);
		add(x, y);
	}
	topsort();
	
	int ans = 0;
	for(int i = 1; i <= n; i ++)
		ans = ans > num[i] ? ans : num[i];
	printf("%d", ans);
	return 0;	
}

你可能感兴趣的:(数据结构)