7.26学习笔记
主要内容:
1.堆
2.并查集
3.线段树
4.可持久化线段树
5.树状数组
优先队列:
优先队列定义: priority_queue<Type, Container, Functional>
tips:Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,
但不能用 list。STL里面默认用的是vector),Functional 就是比较函数,当需要用自定义的数据类型时才需要
传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。
priority_queue <int, vector<int>, greater<int> > q; //升序队列
priority_queue <int, vector<int>, less<int> >q; //降序队列
结构体创建优先队列:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
int N, M, K;
struct Student
{
int id;
int arrive_time;
int office_num;
int finish_time;
std::vector<pair<int, int> > register_offices;
};
Student students[10005];
struct Event
{
int student_idx;
int office;
int begin;
int duration;
Event(int s, int o, int b, int d): student_idx(s), office(o), begin(b), duration(d){};
};
struct Cmp
{
bool operator()(const Event &e1, const Event &e2){
if (e1.begin == e2.begin)
return students[e1.student_idx].id > students[e2.student_idx].id;
return e1.begin > e2.begin;
}
};
priority_queue<Event, vector<Event>, Cmp> pq;
int pre[105];
int pos[10005];
void Solve() {
for (int i=0;i<N;++i) {
pq.push(Event(i, students[i].register_offices[0].first, students[i].arrive_time+K, students[i].register_offices[0].second));
pos[i] = 1;
}
memset(pre, -1, sizeof(pre));
while (!pq.empty()) {
Event e = pq.top();
pq.pop();
int st = e.student_idx;
if (pre[e.office] > e.begin) {
e.begin = pre[e.office];
}
int finish_time = e.begin + e.duration;
if (pos[st] == students[st].office_num) {
students[st].finish_time = finish_time;
} else {
int office = students[st].register_offices[pos[st]].first;
int duration = students[st].register_offices[pos[st]].second;
pq.push(Event(st, office, finish_time+K, duration));
pos[st]++;
}
pre[e.office] = finish_time;
}
}
int main()
{
scanf("%d%d%d", &N, &M, &K);
int p, o, w;
for (int i=0;i<N;++i) {
scanf("%d%d%d", &students[i].id, &students[i].arrive_time, &p);
students[i].office_num = p;
for (int j=0;j<p;++j) {
scanf("%d%d", &o, &w);
students[i].register_offices.push_back(make_pair(o, w));
}
}
Solve();
for (int i=0;i<N;++i) {
printf("%d\n", students[i].finish_time);
}
return 0;
}
堆排序模板:
#include <algorithm>
#include <cstdio>
using namespace std;
int x,size,n;
int heap[1000005];
void push(int x)
{
int now,next;
heap[++size]=x;
now=size;
while(now>1)
{
next=now/2;
if(heap[next]<=heap[now]) return ;
swap(heap[next],heap[now]);
now=next;
}
}
int pop()
{
int now,next;
int ret=heap[1];
heap[1]=heap[size--];
now=1;
while(now*2<=size)
{
next=now*2;
if(next<size&&heap[next]>heap[next+1]) next++;
if(heap[now]<=heap[next]) return ret;
swap(heap[now],heap[next]);
now=next;
}
return ret;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
push(x);
}
for(int i=1;i<n;i++)
{
int ans=pop();
printf("%d ",ans);
}
printf("%d\n",pop());
return 0;
}
并查集
定义:
并查集是一种多叉树,用于处理一些不相交集合的合并及查询问题。
1.初始化:每个结点单独作为一个集合。
2.查询:求元素所在的集合的代表元素,即根结点。
3.合并:将两个元素所在的集合,合并为一个集合。
线段树
定义:
线段树是一种二叉搜索树(实质是平衡二叉树),线段树的每个结点都存
储了一个区间,也可以理解成一个线段。
P3372 【模板】线段树 1
题目描述
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 kk。
- 求出某区间每一个数的和。
输入格式
第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:
1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。2 x y:输出区间 [x, y][x,y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
输入输出样例
5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4
11 8 20
说明/提示
对于 30\%30% 的数据:n \le 8n≤8,m \le 10m≤10。
对于 70\%70% 的数据:n \le {10}^3n≤103,m \le {10}^4m≤104。
对于 100\%100% 的数据:1 \le n, m \le {10}^51≤n,m≤105。
保证任意时刻数列中任意元素的和在 [-2^{63}, 2^{63})[−263,263) 内。
【样例解释】

#include<bits/stdc++.h>
#define LL long long
using namespace std;
struct cs {
LL ll,rr,vv;
} T[824290];
LL a[200005],v[824290];
LL n,m,x,y,z,sum,N;
void clean(LL x) {
if(!v[x])return;
T[x].vv+=(T[x].rr-T[x].ll+1)*v[x];
if(T[x].ll!=T[x].rr) {
v[x*2]+=v[x];
v[x*2+1]+=v[x];
}
v[x]=0;
}
void maketree(LL x,LL y,LL num) {
T[num].ll=x;
T[num].rr=y;
if(x==y) {
T[num].vv=a[x];
return;
}
maketree(x,(x+y)/2,num*2);
maketree((x+y)/2+1,y,num*2+1);
T[num].vv=T[num*2].vv+T[num*2+1].vv;
}
void inc(LL x,LL y,LL z,LL num) {
clean(num);
if(x<=T[num].ll&&T[num].rr<=y) {
v[num]+=z;
return;
}
T[num].vv+=(min(y,T[num].rr)-max(x,T[num].ll)+1)*z;
if(T[num].ll==T[num].rr) return;
int mid=(T[num].ll+T[num].rr)/2;
if(x>mid)inc(x,y,z,num*2+1);
else if(y<=mid)inc(x,y,z,num*2);
else {
inc(x,y,z,num*2);
inc(x,y,z,num*2+1);
}
}
void out(int LL,int LL,LL num) {
clean(num);
if(x<=T[num].ll&&T[num].rr<=y) {
sum+=T[num].vv;
return;
}
int mid=(T[num].ll+T[num].rr)/2;
if(x>mid)out(x,y,num*2+1);
else if(y<=mid)out(x,y,num*2);
else {
out(x,y,num*2);
out(x,y,num*2+1);
}
}
int main() {
scanf("%d%d",&n,&N);
for(int i=1; i<=n; i++)scanf("%d",&a[i]);
maketree(1,n,1);
for(int i=1; i<=N; i++) {
scanf("%d%d%d",&m,&x,&y);
if(m==1) {
scanf("%d",&z);
inc(x,y,z,1);
} else {
sum=0;
out(x,y,1);
printf("%lld\n",sum);
}
}
return 0;
}


浙公网安备 33010602011771号