再闻已是曲中人

无法言说

文章目录

  • 奇技淫巧
    • 对拍
    • 数据生成
      • 随机树
      • 长毛树
      • 菊花图
      • 双星树
      • 蜘蛛树
    • 伪去重离散化
    • 手写abs
    • 手写swap
    • 判断整数奇偶
    • 判断两数是否同号
    • 构造函数重载运算符
  • 图论
    • 欧拉图
      • 欧拉回路
      • 欧拉通路
    • Topsort
      • 求最长拓扑链
    • 生成树
      • 最小生成树
        • 堆优化Prim
        • Kruskal
      • 瓶颈生成树
        • Kruskal求瓶颈生成树
      • 最小瓶颈路
        • 解法
      • 非严格次小生成树
        • 解法
      • 最小增量生成树
        • 解法
    • 最短路
      • Floyd
      • Dijkstra
      • SPFA
    • 差分约束
    • Tarjan
      • 缩点
      • 求联通分量
    • 数据结构
      • 线段树

奇技淫巧

对拍

#include
#include
#include
using namespace std;
int main()
{
    for(;;)
    {
    	system("datamaker.exe > data.in");//启动数据生成器 
        system("my.exe < data.in > my.out");//启动“正解”和”暴力“ 
        system("std.exe < data.in > std.out");
        if(system("fc my.out std.out"))//如果出锅,就停下来 
			return-1;
	}
	return 0;
}

或者

#include
#include
#include
using namespace std;
int main()
{
    for(;;)
    {
        system("start datamaker.exe");//启动数据生成器 
        Sleep(500);//等待数据输出(极限数据输出大约0.5s) 
        system("start my.exe");//启动“正解”和”暴力“ 
        system("start std.exe");
        Sleep(100);//这个时间取决于你写的暴力的最坏时间 
        if(system("fc my.out std.out"))//如果出锅,就停下来 
        {
            system("pause");
            break;
        }
    }
	return 0;
}

数据生成

注意审题!根据题目决定是否加入重边或自环

随机树

#include
int const maxn=111;
int const N=10;
int const M=25;
int const C=10;
std::stringstream str;
int seed;
int n,a[maxn];
int main(int argc,char *argv[])
{
	seed=time(NULL);
	if(argc)
	{
        str.clear();
        str<>seed;
    }
    srand(seed);
    n=rand()%N+C+1;
    printf("%d\n",n); 
	for(int i=2;i<=n;i++)
	{
		int	x=rand()%i+1;
		if(x==i)
			x--;
		printf("%d %d\n",i,x);
	}
	return 0;
}

长毛树

#include
int const maxn=111;
int const N=10;
int const M=25;
int const C=10;
std::stringstream str;
int seed;
int n,a[maxn];
int main(int argc,char *argv[])
{
	seed=time(NULL);
	if(argc)
	{
        str.clear();
        str<>seed;
    }
    srand(seed);
    n=rand()%N+C+1;
	for(int i=1;i<=n;i++)
		a[i]=i;
	std::random_shuffle(a+1,a+1+n);
	for(int i=2;i<=C;i++)
		printf("%d %d\n",a[i],a[i-1]);
	for(int i=C+1;i<=n;i++)
	{
		int x=rand()%a[i]+1;
		printf("%d %d\n",i,x);
	}
	return 0;
}

菊花图

#include
int const maxn=111;
int const N=10;
int const M=25;
int const C=10;
std::stringstream str;
int seed;
int n,a[maxn];
int main(int argc,char *argv[])
{
	seed=time(NULL);
	if(argc)
	{
        str.clear();
        str<>seed;
    }
    srand(seed);
    n=rand()%N+C;
    printf("%d\n",n); 
 	for(int i=1;i

双星树

#include
int const maxn=111;
int const N=10;
int const M=25;
int const C=5;
std::stringstream str;
int seed;
int n,a[maxn],vis[maxn];
int cnt1,cnt2;
int main(int argc,char *argv[])
{
	seed=time(NULL);
	if(argc)
	{
        str.clear();
        str<>seed;
    }
    srand(seed);
    n=rand()%N+2*C;
    printf("%d\n",n); 
    int root1=rand()%n+1;
    int root2=rand()%n+1;
    if(root1==root2)
    	root2=(root2+1)%n+1; 
    printf("%d %d\n",root1,root2);
    vis[root1]=vis[root2]=true;
 	for(int i=1;i<=n;i++)
 		a[i]=i;
 	std::random_shuffle(a+1,a+1+n);
 	for(int i=1;i<=n;i++)
 	{
 		if(cnt1==C)
 			break;
 		if(vis[a[i]])
 			continue;
	 	cnt1++;printf("%d %d\n",root1,a[i]);
		vis[a[i]]=true;
 	}
 	for(int i=1;i<=n;i++)
 	{
 		if(cnt2==C)
 			break;
 		if(vis[a[i]])
 			continue;
		cnt2++,printf("%d %d\n",root2,a[i]);
		vis[a[i]]=true;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[a[i]])
 			continue;
 		int x=rand()%a[i]+1;
 		printf("%d %d\n",a[i],x);
 	}
	 return 0;
}

蜘蛛树

#include
int const maxn=111;
int const N=10;
int const M=25;
int const C=5;
std::stringstream str;
int seed;
int n,a[maxn],vis[maxn];
int cnt1,cnt2;
int main(int argc,char *argv[])
{
	seed=time(NULL);
	if(argc)
	{
        str.clear();
        str<>seed;
    }
    srand(seed);
    n=rand()%N+3*C;
    printf("%d\n",n);
    for(int i=1;i<=C;i++)
    	printf("%d %d\n",i,i+1),vis[i]=true,vis[i+1]=true;
    int root1=rand()%n+1;
    while(vis[root1])
    	root1=rand()%n+1;
    vis[root1]=true;
    int root2=rand()%n+1;
    while(vis[root2])
    	root2=rand()%n+1;
    vis[root2]=true;
    printf("%d %d\n%d %d\n",root1,1,root2,C+1);
    vis[root1]=vis[root2]=true;
 	for(int i=1;i<=n;i++)
 		a[i]=i;
 	std::random_shuffle(a+1,a+1+n);
 	for(int i=1;i<=n;i++)
 	{
 		if(cnt1==C)
 			break;
 		if(vis[a[i]])
 			continue;
	 	cnt1++;printf("%d %d\n",root1,a[i]);
		vis[a[i]]=true;
 	}
 	for(int i=1;i<=n;i++)
 	{
 		if(cnt2==C)
 			break;
 		if(vis[a[i]])
 			continue;
		cnt2++,printf("%d %d\n",root2,a[i]);
		vis[a[i]]=true;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[a[i]])
 			continue;
 		int x=rand()%a[i]+1;
 		printf("%d %d\n",a[i],x);
 	}
	 return 0;
}

伪去重离散化

//unique(u,v)返回去重(伪)后的地址+1,被删掉的会加到后面,以返回值为首地址
int const maxn=1e5+10;
int a[maxn], t[maxn];
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
    scanf("%d",a[i]),t[i]=a[i];
sort(t+1,t+n+1);//排序,找相对大小
m=unique(t+1,t+1+n)-t-1;//m为不重复的元素的个数
for(int i=1; i<=n; i++)
    a[i]=lower_bound(t+1,t+1+m,a[i])-t;//返回b中第一个大于等于a[i]的位置

手写abs

  • 整数范围 int abs(int x){ return (x^(x>>31))-(x>>31);}
  • 实数范围double abs(double x){ return x>esp:x?-x;}

手写swap

void swap(int &a,int &b){a^=b;b^=a;a^=b;}

判断整数奇偶

int pan(int x){return x&1;}

判断两数是否同号

int pan(int x,int y){return !((x^y)>>31);}

构造函数重载运算符

struct node
{
    int nd,dis;
    bool operator<(const node &b)const
    {
        return dis>b.dis;
    }
    //从大到小排序
    node(int nd=0,int dis=0):
        nd(nd),dis(dis){}
};

图论

欧拉图

欧拉回路

欧拉通路

Topsort

解决具有严格更新顺序的图论问题
一般结合DP使用(如树形DP)

void topsort(int s)
{
	std::queueq;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			ind[v]--;
			f[v]=f[u]+change;
			if(!ind[v])
				q.push(v);
		}
	}
}

求最长拓扑链

把queue改成结构体,跑topsort的时候顺便维护一下深度

生成树

最小生成树

堆优化Prim

prim每次找到集合内到集合外的最短边
这样我们就可以把每个点扩展到的边压成点放进小根堆里堆里
如果u已经在集合内,直接continue
每次取堆顶即可

struct node
{
	int id,dis;
	bool operator <(const node &b)const
	{
		return dis>b.dis;
		//优先队列默认大根堆
		//这里把他重载成小根堆
	}
	node(int id=0,int dis=0):
		id(id).dis(dis){}
};
void prim(int s)
{
	std::priority_queueq;
	q.push(node(s,0));
	cost[s]=0;
	while(!q.empty())
	{
		int u=q.top().id,dis=q.top().dis;
		q.pop();
		if(set[u])
			continue;
		ans+=dis;
		set[u]=true;
		//注意,dijkstra可以不加访问标记,因为dijkstra能保证每个点只入队一次
		//prim则不能保证
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to,w=e[i].w;
			if(cost[v]>w)
				cost[v]=w,q.push(node(v,w));
		}
	}
	printf("%d",ans);
}

Kruskal

int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
int cmp(RE x,RE y)
{
	return x.w

瓶颈生成树

无向图 G G G的一颗瓶颈生成树是这样的一颗生成树,
它最大的边权值在 G G G的所有生成树中是最小的。瓶颈生成树的值为T中最大权值边的权。
最小生成树一定是瓶颈生成树
瓶颈生成树不一定是最小生成树

Kruskal求瓶颈生成树

由于kruskal的性质,第一棵求出的生成树就是瓶颈生成树

最小瓶颈路

最小瓶颈路问题是指在一张无向图中,有多组询问,每组询问提供一个一个点对 ( u , v ) (u,v) (u,v),需要找出从 u u u v v v的一条简单路径,使路径上所有边中最大值最小

解法

最小生成树中u到v的路径一定是最小瓶颈路之一
因此我们可以先搞一棵 M S T MST MST,然后问题转化为了求 M S T MST MST ( u , v ) (u,v) (u,v)的最大边权
这个用倍增LCA或者树剖都能搞

非严格次小生成树

求出一棵生成树,其所有边的权值之和仅次于最小生成树的权值之和

解法

先求出 M S T MST MST,然后枚举加入不在 M S T MST MST上的边,这样势必会构成环,我们则需要在环上断开一条边回到树形结构
自此问题转化为求 M S T MST MST ( u , v ) (u,v) (u,v)两个点之间的最大边权,这显然是个最小瓶颈路问题,解法同上

最小增量生成树

从包含n个点的空图开始,依次加入m条带权边。每加入一条边输出当前图的最小生成树的权值,不连通输出无解

解法

int main()
{
	scanf("%d%d"&n,&m);
	for(int u,v,w,i=1;i<=m;i++)
	{
		scanf("%d%d%d“,&u,&v,&w1);
		if(num=n-1)
			printf("%d\n",MST);
		num++;
	}	
}

最短路

Floyd

Dijkstra

SPFA

差分约束

Tarjan

缩点

求联通分量

数据结构

线段树

#include
int const maxn=111;
struct Tree
{
	int lc,rc,sum,tag;
}a[maxn<<1];
int t=1;
int w[maxn];
void pushup(int u)
{
	a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;
}
void build(int u,int l,int r)
{
	if(l==r)
	{
		a[u].sum=w[l];return;
	}
	int mid=l+r>>1;
	a[u].lc=++t;
	build(a[u].lc,l,mid);
	a[u].rc=++t;
	build(a[u].rc,mid+1,r);
	pushup(u);
}
void pushdown(int u,int l,int r)
{
	int lc=a[u].lc,rc=a[u].rc,tag=a[u].tag;
	int mid=l+r>>1;
	a[lc].sum+=tag*(mid-l+1);
	a[lc].tag+=tag;
	a[rc].sum+=tag*(mid-r);
	a[rc].tag+=tag;
	a[u].tag=0;
}
void update_plus(int u,int l,int r,int ll,int rr,int dlt)
{
	if(l==ll&&r==rr)
	{
		a[u].sum+=dlt*(l-r+1);
		a[u].tag+=dlt;
		return;
	}
	pushdown(u,l,r);
	int mid=l+r>>1;
	if(rr<=mid)
		update_plus(a[u].lc,l,mid,ll,rr,dlt);
	else if(ll>mid)
		update_plus(a[u].rc,mid+1,r,ll,rr,dlt);
	else
		update_plus(a[u].lc,l,mid,ll,mid,dlt),update_plus(a[u].rc,mid+1,r,mid+1, rr,dlt);
	pushup(u);
}
int query(int u,int l,int r,int ll,int rr)
{
	if(l==ll&&r==rr)
		return a[u].sum;
	pushdown(u,l,r);
	int mid=l+r>>1;
	return rr<=mid?query(a[u].lc,l,mid,ll,rr):(ll>mid?query(a[u].rc,mid+1,r,ll,rr):query(a[u].lc,l,mid,ll,mid)+query(a[u].rc,mid+1,r,mid+1,rr));
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	build(1,1,n); 
	for(int op,x,y,z,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)
		{
			scanf("%d",&z);
			update_plus(1,1,n,x,y,z);
		}
		else
			printf("%d\n",query(1,1,n,x,y));
	}
	return 0;
}

你可能感兴趣的:(奇技淫巧,noip)