• 奇技淫巧and板子


    本文将记录一些奇技淫巧和板子(最基础的也有),先从今天开始写,以前的找个时间再补上

    杂项

    (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) ]

    例题

  • 相关阅读:
    EL表达式
    JavaBean知识
    设计模型MVC和JavaBean
    JSP知识
    会话技术
    Servlet知识
    selenium+maven+testng+IDEA+git+jenkins自动化测试环境搭建(三)
    selenium+maven+testng+IDEA+git自动化测试环境搭建(二)
    selenium+testng+testng-xslt-1.1.2之报告完善
    selenium入门环境之浏览器问题
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/11669535.html
Copyright © 2020-2023  润新知