目录
本文将记录一些奇技淫巧和板子(最基础的也有),先从今天开始写,以前的找个时间再补上
杂项
(2020.4.29之前写的)没有系统的提纲,很杂乱,没什么看点,因此以后的会整理一下
求第(k)大的数
应用快速排序思想((O(n))),平常都是(O(nlogn))
基于快排的思想,在每一层递归中,随机选取一个数做基准时,统计出大于基准值的数的个数(cnt),如果(k<=cnt)就在左半段(比基准数大)中寻找第(k)大的数,反之则在右半段寻找第(k-cnt)大的数
复杂度证明:
因为每次只进入了左右两段的任意一个,则在平均情况之下复杂度为:(n+frac{n}{2}+frac{n}{3}+.....+1=O(n))
求长度不小于L的子段使之和最大
ST表
预处理
void st_prework() {
for(int i=1; i<=n; ++i) f[i][0]=a[i];
for(int j=1; j<=21; ++j)
for(int i=1; i+(1<<j)-1<=n; ++i)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
查询
int query(int l,int r) {
int res=-9999;
int k=0;
while((1<<(k+1)<=r-l+1)) k++;
res=max(f[l][k],f[r-(1<<k)+1][k]);
return res;
}
(O(1))实现能查询栈中最小元素
开两个栈,a存原始数据,b存历史上每个时刻的最小值
举个例子
a:9 2 1 5 3 0 2 <-
b:9 2 1 1 1 0 0 <-
每次插入元素x时,a插入x,b插入min(top(b),x),弹出时一起弹,询问时输出top(b)
二分
之前用的二分太傻比了,需要考虑的东西太多(可是我没有脑子),学长就教了一个咕咕咕的二分
int l=0,r=1e18;//取个大一点的数
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans;
double l=0,r=1e18;//取个大一点的数
while(r-l<=eps)
{
double mid=(l+r)/2;
if(check(mid)) r=mid,ans=mid;
else l=mid;
}
cout<<ans;
树和图的深度优先遍历和广度优先遍历
//dfs
void dfs(int x)
{
visit[x]=1;
for(int i=head[x];i;i=e[i].Next)
{
int to=e[i].v;
if(visit[to]) continue;
dfs(to);
}
}
//bfs
void bfs()
{
queue<int>q;
q.push(1);
d[1]=1;//层数
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].Next)
{
int to=e[i].v;
if(visit[to]) continue;
d[to]=d[u]+1;
q.push(to);
}
}
}
树的dfs序
dfs序的特点:
每个节点x编号在序列中出现两次,而且以这两次出现位置为端点的闭区间就是以x为根的子树的DFS序
void dfs(int x)
{
a[++len]=x;//记录dfs序
visit[x]=1;
for(int i=head[x];i;i=e[i].Next)
{
int to=e[i].v;
if(visit[to]) continue;
dfs(to);
}
a[++len]=x;
}
求树的重心
void dfs(int x)
{
int max_part=0;//删除掉x后最大子树大小
size[x]=1;//子树x的大小
visit[x]=1;
for(int i=head[x];i;i=e[i].Next)
{
int to=e[i].v;
if(visit[to]) continue;
dfs(to);
size[x]+=size[y];
max_part=max(max_part,size[y]);
}
max_part=max(max_part,n-size[x]);//n为整颗树的节点数目
if(max_part<ans)
{
ans=max_part;//记录重心对应的max_part值
pos=x;//记录重心编号
}
}
图的联通块划分
void dfs(int x)
{
visit[x]=cnt;
for(int i=head[x];i;i=e[i].Next)
{
int to=e[i].v;
if(visit[to]) continue;
dfs(to);
}
}
for(int i=1;i<=n;++i)
if(!visit[i]) cnt++,dfs(i);
拓扑排序
void topsort()
{
queue<int>q;
for(int i=1;i<=n;++i)
if(du[i]==0) q.push(i);//du在add时记录
while(!q.empty())
{
int u=q.front();
q.pop();
a[++len]=u;//记录拓扑序
for(int i=head[u];i;i=e[i].Next)
{
int to=e[i].v;
if(--du[to]==0) q.push(to);
}
}
}
使用负数下表
int * z=y+50
z[50]-->y[0]
treap平衡树
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2019;
const int INF=(1<<30);
int sum=0,R=0;
int size[N],v[N],num[N],rd[N],son[N][2];
void pushup(int p) {
size[p]=size[son[p][0]]+size[son[p][1]]+num[p];
}
void rotate(int &p,int d) {
int k=son[p][d^1];
son[p][d^1]=son[k][d];
son[k][d]=p;
pushup(p),pushup(k);
p=k;
}
void ins(int &p,int x) {
if(!p) {
p=++sum;
size[p]=num[p]=1;
v[p]=x,rd[p]=rand();
return ;
}
if(v[p]==x) {
num[p]++,size[p]++;
return ;
}
int d=(x>v[p]);
ins(son[p][d],x);
if(rd[p]<rd[son[p][d]]) rotate(p,d^1);
pushup(p);
}
void del(int &p,int x) {
if(!p) return ;
if(x<v[p]) del(son[p][0],x);
else if(x>v[p]) del(son[p][1],x);
else {
if(!son[p][0]&&!son[p][1]) {
num[p]--,size[p]--;
if(num[p]==0) p=0;
} else if(son[p][0]&&!son[p][1]) {
rotate(p,1);
del(son[p][1],x);
} else if(!son[p][0]&&son[p][1]) {
rotate(p,0);
del(son[p][0],x);
} else if(son[p][0]&&son[p][1]) {
int d=(rd[son[p][0]]>rd[son[p][1]]);
rotate(p,d);
del(son[p][d],x);
}
}
pushup(p);
}
int paiming(int p,int x)
{
if(!p) return 0;
if(v[p]==x) return size[son[p][0]]+1;
if(v[p]<x) return size[son[p][0]]+num[p]+paiming(son[p][1],x);
if(v[p]>x) return paiming(son[p][0],x);
}
int find(int p,int x)
{
if(!p) return 0;
if(size[son[p][0]]>=x) return find(son[p][0],x);
else if(size[son[p][0]]+num[p]<x) return find(son[p][1],x-num[p]-size[son[p][0]]);
else return v[p];
}
int pre(int p,int x)
{
if(!p) return -INF;
if(v[p]>=x) return pre(son[p][0],x);
else return max(v[p],pre(son[p][1],x));
}
int Next(int p,int x)
{
if(!p) return INF;
if(v[p]<=x) return Next(son[p][1],x);
else return min(v[p],Next(son[p][0],x));
}
int main() {
int n;
scanf("%d",&n);
for (int i=0; i<n; ++i) {
int opt,x;
scanf("%d%d",&opt,&x);
if (opt==1) ins(R,x);
else if (opt==2) del(R,x);
else if (opt==3) printf("%d
",paiming(R,x));
else if (opt==4) printf("%d
",find(R,x));
else if (opt==5) printf("%d
",pre(R,x));
else if (opt==6) printf("%d
",Next(R,x));
}
return 0;
}
fhq treap
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2019;
struct node {
int l,r;
int val,key;
int size;
} fhq[N];
int T;
int cnt,root;
int nownode(int val) {
fhq[++cnt].val=val;
fhq[cnt].size=1;
fhq[cnt].key=rand();
return cnt;
}
void update(int p) {
fhq[p].size=fhq[fhq[p].l].size+fhq[fhq[p].r].size+1;
}
void spilt(int now,int val,int &x,int &y) {//x和y是拆分后两树的根节点
if(!now) x=y=0;
else {
if(fhq[now].val<=val) {
x=now;
spilt(fhq[now].r,val,fhq[now].r,y);//拆分右子树,因为右子树中可能还存在比val小的节点
} else {
y=now;
spilt(fhq[now].l,val,x,fhq[now].l);//复读机
}
update(now);
}
}
int merge(int x,int y) {
if(!x||!y) return x+y;
if(fhq[x].key>fhq[y].key) { //维护根的性质
//根据堆的性质得到的新树x在y上面,而且根据二叉搜索树的性质y一定在x下面,所有y在x右下
fhq[x].r=merge(fhq[x].r,y);
update(x);
return x;
} else { //复读机
fhq[y].l=merge(x,fhq[y].l);
update(y);
return y;
}
}
int x,y,z;
void ins(int val) {
spilt(root,val,x,y);
root=merge(merge(x,nownode(val)),y);//这里忘给root负值了
}
void del(int val) {
spilt(root,val,x,z);
spilt(x,val-1,x,y);
y=merge(fhq[y].l,fhq[y].r);
root=merge(merge(x,y),z);
}
int getrank(int val) {
spilt(root,val-1,x,y);
int ret=fhq[x].size+1;
root=merge(x,y);//先return再合并
return ret;
}
int getnum(int pm) {
int now=root;
while(now) {
if(fhq[fhq[now].l].size+1==pm) break;
else if(fhq[fhq[now].l].size>=pm) now=fhq[now].l;
else {
pm-=fhq[fhq[now].l].size+1;
now=fhq[now].r;
}
}
return fhq[now].val;
}
int pre(int val) {
spilt(root,val-1,x,y);
int now=x;
while(fhq[now].r) now=fhq[now].r;
int ret=fhq[now].val;
root=merge(x,y);
return ret;
}
int Next(int val) {
spilt(root,val,x,y);
int now=y;
while(fhq[now].l) now=fhq[now].l;
int ret=fhq[now].val;
root=merge(x,y);
return ret;
}
int main() {
srand((unsigned)time(0));
scanf("%d",&T);
while(T--) {
int opt,x;
scanf("%d%d",&opt,&x);
if(opt==1) ins(x);
if(opt==2) del(x);
if(opt==3) cout<<getrank(x)<<'
';
if(opt==4) cout<<getnum(x)<<'
';
if(opt==5) cout<<pre(x)<<'
';
if(opt==6) cout<<Next(x)<<'
';
}
return 0;
}
可能是splay
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2019;
const int INF=(1<<30);
int sum=0,R=0;
int size[N],v[N],num[N],rd[N],son[N][2];
void pushup(int p) {
size[p]=size[son[p][0]]+size[son[p][1]]+num[p];
}
void rotate(int &p,int d) {
int k=son[p][d^1];
son[p][d^1]=son[k][d];
son[k][d]=p;
pushup(p),pushup(k);
p=k;
}
void ins(int &p,int x) {
if(!p) {
p=++sum;
size[p]=num[p]=1;
v[p]=x,rd[p]=rand();
return ;
}
if(v[p]==x) {
num[p]++,size[p]++;
return ;
}
int d=(x>v[p]);
ins(son[p][d],x);
if(rd[p]<rd[son[p][d]]) rotate(p,d^1);
pushup(p);
}
void del(int &p,int x) {
if(!p) return ;
if(x<v[p]) del(son[p][0],x);
else if(x>v[p]) del(son[p][1],x);
else {
if(!son[p][0]&&!son[p][1]) {
num[p]--,size[p]--;
if(num[p]==0) p=0;
} else if(son[p][0]&&!son[p][1]) {
rotate(p,1);
del(son[p][1],x);
} else if(!son[p][0]&&son[p][1]) {
rotate(p,0);
del(son[p][0],x);
} else if(son[p][0]&&son[p][1]) {
int d=(rd[son[p][0]]>rd[son[p][1]]);
rotate(p,d);
del(son[p][d],x);
}
}
pushup(p);
}
int paiming(int p,int x)
{
if(!p) return 0;
if(v[p]==x) return size[son[p][0]]+1;
if(v[p]<x) return size[son[p][0]]+num[p]+paiming(son[p][1],x);
if(v[p]>x) return paiming(son[p][0],x);
}
int find(int p,int x)
{
if(!p) return 0;
if(size[son[p][0]]>=x) return find(son[p][0],x);
else if(size[son[p][0]]+num[p]<x) return find(son[p][1],x-num[p]-size[son[p][0]]);
else return v[p];
}
int pre(int p,int x)
{
if(!p) return -INF;
if(v[p]>=x) return pre(son[p][0],x);
else return max(v[p],pre(son[p][1],x));
}
int Next(int p,int x)
{
if(!p) return INF;
if(v[p]<=x) return Next(son[p][1],x);
else return min(v[p],Next(son[p][0],x));
}
int main() {
int n;
scanf("%d",&n);
for (int i=0; i<n; ++i) {
int opt,x;
scanf("%d%d",&opt,&x);
if (opt==1) ins(R,x);
else if (opt==2) del(R,x);
else if (opt==3) printf("%d
",paiming(R,x));
else if (opt==4) printf("%d
",find(R,x));
else if (opt==5) printf("%d
",pre(R,x));
else if (opt==6) printf("%d
",Next(R,x));
}
return 0;
}
位运算
补码
(c)按位取反后结果为(-1-c)
一个小技巧
[(a+y)^x=a^x (mod y)
]