MangataのACM模板
Posted MangataTS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MangataのACM模板相关的知识,希望对你有一定的参考价值。
本篇文章主要是Mangata平时写代码所用到的代码模板库,如有不对请在评论区指出
先放一个我的 常数优化的博客: 传送门
再放一个我的 代码格式博客: 传送门
数据结构
并查集
并查集是一种集合数据结构,通过并查集我们可以快速查询两个元素是否是一个集合,下面是Mangata常用的板子
/*
作者:Mangata
路径压缩并查集
*/
#include<cstdio>
const int N = 10005;//节点数
int fa[N],n;
void init(int len) {//初始化,先让每个位置的父节点等于自身
for(int i=0; i<=n; ++i)
fa[i] = i;
}
int find(int x) {//查找x的祖先节点
int t = x;//路径压缩
while(t != fa[t])
t = fa[t];
while(x != fa[x]) {
int temp = fa[x];
fa[x] = t;
x = temp;
}
return x;
}
void merge(int a,int b) {//将x和y合并
a=find(a),b=find(b);
if(a != b) {
fa[b] = a;
n--;
}
}
int main()
{
int t,m,a,b;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
init(n);
for(int i = 1; i <= m; ++i) {
scanf("%d%d",&a,&b);
merge(a,b);
}
printf("%d\\n",n);//输出不同类别的总数目
}
return 0;
}
树状数组
二维单点修改,区间查询
例题:传送门
Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 5000;
ll tree[N][N<<2];
int n,m;
int lowbit(int x) {
return -x & x;
}
inline void updata(int x,int y,int k) {
while(x <= n) {
int temp = y;
while(y <= m) {
tree[x][y] += k;
y += lowbit(y);
}
x += lowbit(x);
y = temp;
}
}
inline ll get(int x,int y) {
ll ans = 0;
while(x) {
int temp = y;
while(y) {
ans += tree[x][y];
y -= lowbit(y);
}
x -= lowbit(x);
y = temp;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
int a,b,c,d,op;
while(~scanf("%d",&op)) {
if(op == 1) {
scanf("%d%d%d",&a,&b,&c);
updata(a,b,c);
}
else {
scanf("%d%d%d%d",&a,&b,&c,&d);
printf("%lld\\n",get(c,d)-get(c,b-1)-get(a-1,d) + get(a-1,b-1));
}
}
return 0;
}
线段树
单点修改,区间查询
例题:HDU1754
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2000005;
int n,m;
int a[N],tree[N << 2];
void push_up(int k) {
tree[k] = max(tree[k<<1],tree[k<<1|1]);
}
void build(int k, int l,int r) {
if(l == r) {
tree[k] = a[l];
}
else {
int mid = l + ((r-l)>>1);
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
push_up(k);
}
}
void updata(int p,int v,int l,int r,int k) {
if(l == r) {
a[p] += v, tree[k] += v;
}
else {
int mid = l + ((r-l)>>1);
if(p <= mid) {
updata(p,v,l,mid,k<<1);
}
else {
updata(p,v,mid+1,r,k<<1|1);
}
push_up(k);
}
}
int query(int L, int R,int l,int r,int k) {
if(L <= l && R >= r) {
return tree[k];
}
else {
int ans = -INF;
int mid = l+r >>1;
if(L <= mid) {
ans = max(ans,query(L,R,l,mid,k<<1));
}
if(R > mid) {
ans = max(ans,query(L,R,mid+1,r,k<<1|1));
}
return ans;
}
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
for(int i = 1;i <= n; ++i) {
scanf("%d",&a[i]);
}
build(1,1,n);
char op;
int l,r;
while(m--) {
cin>>op;
if(op == 'Q') {
scanf("%d%d",&l,&r);
printf("%d\\n",query(l,r,1,n,1));
}
else if(op == 'U'){
scanf("%d%d",&l,&r);
updata(l,r-a[l],1,n,1);
}
}
}
return 0;
}
区间更新、区间查询
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6+10;
ll tree[N<<2],tag[N<<2];
ll a[N];
inline ll ls(ll p) {return p<<1;}
inline ll rs(ll p) {return p<<1|1;}
void push_up_min(ll p) {//向上更新操作
tree[p] = min(tree[ls(p)],tree[rs(p)]);
}
void build(ll p,ll l,ll r) {//建树操作
if(l == r) {
tree[p] = a[l];
return;
}
ll mid = l + r >> 1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up_min(p);
}
inline void push_down(ll p,ll l,ll r) {//向下更新操作
if(tag[p]) {
tag[ls(p)] += tag[p];
tag[rs(p)] += tag[p];
tree[ls(p)] += tag[p];
tree[rs(p)] += tag[p];
tag[p] = 0;
}
//更新两个儿子节点的tag和tree值
}
void updata(ll L ,ll R ,ll l ,ll r ,ll p ,ll k) {//[L,R]是我们想要修改的区间,
if(L <= l && R >= r) { //[l,r]是我们目前搜索到的区间
tree[p] += k;
tag[p] += k;
return;
}
push_down(p,l,r);//回溯前往下传递更新
ll mid = l + r >> 1;
if(L <= mid) updata(L,R,l,mid,ls(p),k);//如果我们想修改的区间比当前的中间节点小or等于那么就查询
if(R > mid) updata(L,R,mid+1,r,rs(p),k);//如果我们想修改的区间比当前中间节点大那么就查询
push_up_min(p);//回溯后往上传递更新
}
ll query(ll L, ll R,ll l,ll r,ll p) {//[L,R]是我们要查询的区间,[l,r]是当前节点存储的区间
ll res = 0x3f3f3f3f3f3f3f3f;
if(L <= l && R >= r) return tree[p];
ll mid = l + r >> 1;
push_down(p,l,r);
if(L <= mid)
res = min(res,query(L,R,l,mid,ls(p)));
if(R > mid)
res = min(res,query(L,R,mid+1,r,rs(p)));
return res;
}
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; ++i) {
scanf("%lld",&a[i]);
}
build(1,1,n);
int q;
ll l,r,k;
int fg = 0;
for(int i = 1;i <= m; ++i) {
scanf("%lld%lld%lld",&k,&l,&r);
if(fg) continue;
if(query(l,r,1,n,1) >= k)
updata(l,r,1,n,1,-k);
else fg = i;
}
if(fg) {
printf("-1\\n%d\\n",fg);
}
else puts("0");
return 0;
}
主席树(区间第k小数模板)
#include<bits/stdc++.h>
using namespace std;
const int N = 200005;
const int M = 200005;
int n记TJPUのACM新生赛——Stay young, stay simple