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

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 kk。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。
  2. 2 x y:输出区间 [x, y][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例

输入 #1
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出 #1
11
8
20

说明/提示

对于 30\%30% 的数据:n \le 8n8,m \le 10m10。
对于 70\%70% 的数据:n \le {10}^3n103,m \le {10}^4m104。
对于 100\%100% 的数据:1 \le n, m \le {10}^51n,m105。

保证任意时刻数列中任意元素的和在 [-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;
}
posted @ 2022-07-26 21:21  刘炳源  阅读(50)  评论(0)    收藏  举报