我的【模板】

点分治

#include<bits/stdc++.h>
using namespace std;
const int QAQ=2e5+7,ovo=2e5+7;
int n,m,k,ans,siz[QAQ],ma[QAQ],gen;
vector<int> dian[QAQ],bian[QAQ],cun;
bitset<ovo> vis;
int t[ovo];
int lbd(int x) {return x&(-x);}
void jia(int x,int k) {for(int i=x;i<=(2e5);i+=lbd(i)) t[i]+=k;}
int cha(int x) {if(!x) return 1;int da=0;for(int i=x;i;i-=lbd(i)) da+=t[i];return da+1;}

void getrt(int x,int f,int zong)
{
	siz[x]=1,ma[x]=0;
	for(int i=0;i<(int)dian[x].size();i++)
	{
		int v=dian[x][i];
		if(vis[v]||v==f) continue;
		getrt(v,x,zong),siz[x]+=siz[v];
		ma[x]=max(ma[x],siz[v]);
	}
	ma[x]=max(ma[x],zong-siz[x]);
	if(!gen||ma[x]<ma[gen]) gen=x;
}
int cab[QAQ],cnt;
void dfs(int x,int f,int ju)
{
	cab[++cnt]=ju;
	for(int i=0;i<(int)dian[x].size();i++)
	{
		int v=dian[x][i];
		if(vis[v]||v==f) continue;
		dfs(v,x,ju+bian[x][i]);
	}
}
void suan(int x)
{
	cun.clear();
	for(int i=0;i<(int)dian[x].size();i++)
	{
		int v=dian[x][i];
		if(vis[v]) continue;
		cnt=0;
		dfs(v,x,bian[x][i]);
		for(int j=1;j<=cnt;j++) if(k-cab[j]>=0) ans+=cha(k-cab[j]);
		for(int j=1;j<=cnt;j++) if(cab[j]<=k) jia(cab[j],1),cun.push_back(cab[j]);
	}
	for(int i=0;i<(int)cun.size();i++) jia(cun[i],-1);
}
void chuli(int x,int zong)
{
	gen=0,getrt(x,0,zong);
	vis[gen]=1,suan(gen);
	int rt=gen;
	for(int i=0;i<(int)dian[rt].size();i++)
	{
		int v=dian[rt][i];
		if(vis[v]) continue;
		chuli(v,zong-ma[v]);
	}
}
signed main()
{
	 ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1,u,v,w;i<n;i++)
		cin>>u>>v>>w,dian[u].push_back(v),dian[v].push_back(u),
		bian[u].push_back(w),bian[v].push_back(w);
	cin>>k;
	chuli(1,n);
	cout<<ans;
	return 0;
}

单调队列优化四边形不等式

诗人小 G

#include<bits/stdc++.h>
#define int long long
#define ld long double
using namespace std;
const int QAQ=1e5+7;
const int inf=1e18;
int t,n,l,p,d[QAQ],qz[QAQ],s[QAQ],f[QAQ],cnt;
struct xxx {int l,r,k;} z[QAQ];
ld dp[QAQ];
ld ksm(ld x,int k)
{
	ld da=1;
	for(;k;k>>=1,x=x*x) if(k&1) da=da*x;
	return da;
}
ld zhi(int i,int j) {return dp[i]+ksm(abs(qz[j]-qz[i]-1-l),p);}
int erfen(int i,int j)
{
	int l=z[i].l,r=n;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(zhi(z[i].k,mid)>=zhi(j,mid)) r=mid-1;
		else l=mid+1;
	}
	return r;
}
int zb,yb;
void work()
{
	zb=1,yb=0;
	z[++yb]={1,n,0};
	for(int i=1;i<=n;i++)
	{
		while(zb<=yb&&z[zb].r<i) zb++;
		if(zb<=yb) z[zb].l=i;
		dp[i]=zhi(z[zb].k,i);
		f[i]=z[zb].k;
		while(zb<=yb&&zhi(z[yb].k,z[yb].l)>=zhi(i,z[yb].l)) yb--;
		if(zb>yb) yb++,z[yb]={i,n,i};
		else if(zhi(z[yb].k,n)>zhi(i,n))
			z[yb].r=erfen(yb,i),yb++,z[yb]={z[yb-1].r+1,n,i};
	}
}
string a[QAQ];
signed main()
{
	cin>>t;
	for(int i1=1;i1<=t;i1++)
	{
		cin>>n>>l>>p;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			d[i]=a[i].size();
			qz[i]=qz[i-1]+d[i]+1;
		}
		work();
		if(dp[n]<=inf)
		{
			cout<<(int)dp[n]<<"\n";
			cnt=0;
			for(int i=n;i>=1;) s[++cnt]=f[i],i=f[i];
			s[0]=n;
			for(int i=cnt-1;i>=0;i--)
			{
				for(int j=s[i+1]+1;j<=s[i]-1;j++) cout<<a[j]<<" ";
				cout<<a[s[i]]<<"\n";
			}
		}
		else puts("Too hard to arrange");
		puts("--------------------");
	}
	return 0;
}

tarjan

缩点(有向图)

void tajian(int x)
{
	dfn[x]=++hao;
	low[x]=dfn[x];
	zai[x]=1;
	zhan[++top]=x;
	for(int i=head[x];i;i=e[i].nex)
	{
		int v=e[i].to;
		if(!dfn[v]) tajian(v),low[x]=min(low[x],low[v]);
		else if(zai[v]) low[x]=min(low[x],dfn[v]);
	}
	if(dfn[x]==low[x])
	{
		++ke;
		while(zhan[top]!=x)
		{
			kuai[zhan[top]]=ke;
			f[ke]+=a[zhan[top]];
			zai[zhan[top]]=0;
			top--;
		}
		f[ke]+=a[zhan[top]];
		dp[ke]=f[ke];
		kuai[zhan[top]]=ke;
		zai[zhan[top]]=0;
		top--;
	}
}

割点(无向边)

void tajian(int u)
{
	int ji=0;
	dfn[u]=++cnt;low[u]=cnt;
	for(int i=head[u],v;i;i=xia[i])
	{
		if(vis[i^1]) continue; vis[i]=1;
		v=to[i];
		if(!dfn[v])
		{
			tajian(v),low[u]=min(low[u],low[v]);
			if(u!=gen&&low[v]>=dfn[u]) ok[u]=1;
			ji++;
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(u==gen&&ji>1) ok[u]=1;
}

点双(无向边)

void tajian(int u)
{
	int son=0;
	dfn[u]=++cnt;low[u]=cnt;
	zhan[++top]=u;
	for(int i=head[u],v;i;i=xia[i])
	{
		if(vis[i^1]) continue; vis[i]=1;
		v=to[i];
		if(!dfn[v])
		{
			son++,tajian(v),low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				std::vector<int> x;
				x.push_back(u);
				while(zhan[top]!=v) x.push_back(zhan[top--]);
				x.push_back(zhan[top--]);
				ans.push_back(x);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(gen==u&&!son)
	{
		vector<int> x;
		x.push_back(u);
		ans.push_back(x);
	}
}

边双(无向边)

void tajian(int u)
{
	dfn[u]=++cnt;low[u]=cnt;
	zhan[++top]=u;
	for(int i=head[u],v;i;i=xia[i])
	{
		if(vis[i^1]) continue; vis[i]=1;
		v=to[i];
		if(!dfn[v]) tajian(v),low[u]=min(low[u],low[v]);
		else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		vector<int> x=kong;
		while(zhan[top]!=u&&top) x.push_back(zhan[top--]);
		x.push_back(zhan[top--]);
		ans.push_back(x);
	}
}

AC 自动机

#include<bits/stdc++.h>
using namespace std;
const int QAQ=210000;
string t[QAQ],s;
int n,xu[QAQ],ch[QAQ][28],cnt,zhi[QAQ*10],ru[QAQ],ans[QAQ];
vector<int> id[QAQ];
void jia(string s,int lai)
{
	int p=0;
	for(int i=0;i<(int)s.size();i++)
	{
		if(!ch[p][s[i]-'a'+1]) ch[p][s[i]-'a'+1]=++cnt;
		p=ch[p][s[i]-'a'+1];
	}
	id[p].push_back(lai);
}
void pao(string s)
{
	for(int i=0,p=0;i<(int)s.size();i++) p=ch[p][s[i]-'a'+1],zhi[p]++;
}
queue<int> dui;
vector<int> dian[QAQ];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>t[i],jia(t[i],i);
	for(int i=1;i<=26;i++) if(ch[0][i]) dui.push(ch[0][i]),xu[ch[0][i]]=0;
	while(!dui.empty())
	{
		int x=dui.front();dui.pop();
		for(int i=1;i<=26;i++)
		{
			if(ch[x][i]) xu[ch[x][i]]=ch[xu[x]][i],ru[ch[xu[x]][i]]++,dui.push(ch[x][i]);
			else ch[x][i]=ch[xu[x]][i];
		}
	}
	cin>>s,pao(s);
	for(int i=0;i<=cnt;i++) if(ru[i]==0) dui.push(i);
	while(!dui.empty())
	{
		int x=dui.front();dui.pop();
		zhi[xu[x]]+=zhi[x];
		ru[xu[x]]--;
		if(ru[xu[x]]==0) dui.push(xu[x]);
	}
	for(int i=1;i<=cnt;i++) for(int j=0;j<(int)id[i].size();j++) ans[id[i][j]]=zhi[i];
	for(int i=1;i<=n;i++) cout<<ans[i]<<'\n';
	return 0;
}

SPFA

bool vis[110000];
int n,m,s,dis[110000];
vector<int> dian[110000],bian[110000];
void sp(int s)
{
	queue<int> dui;
	dis[s]=0;
	dui.push(s);
	vis[s]=1;
	while(!dui.empty())
	{
		int x=dui.front();dui.pop();
		vis[x]=0;
		int chang=dian[x].size();
		for(int i=0;i<chang;i++)
		{
			int v=dian[x][i];
			if(dis[v]>dis[x]+bian[x][i])
			{
				dis[v]=dis[x]+bian[x][i];
				if(!vis[x]) dui.push(v),vis[v]=1;
			}
		}
	}
}

匈牙利算法

bool vis[51000];
int da,n,m,e,bian[51000];
vector<int> dian[11000];
bool dfs(int x)
{
	int chang=dian[x].size();
	for(int i=0;i<chang;i++)
	{
		int v=dian[x][i];
		if(vis[v]) continue;
		else vis[v]=1;
		if(!bian[v]||dfs(bian[v])) {bian[v]=x;return 1;}
	}
	return 0;
}
int main()
{
	cin>>n>>m>>e;
	for(int i=1,u,v;i<=e;i++) cin>>u>>v,dian[u].push_back(v);
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(dfs(i)) da++;
	}
	cout<<da;
	return 0;
}

exgcd

void exgcd(ll a,ll b)
{
	if(b==0) {x=1,y=0;return;}
	exgcd(b,a%b);
	long long cab=x;
	x=y;
	y=cab-a/b*y;
}//ax+by=gcd(a,b)

数位 DP

int len,f[21][21][21][2][2][2][2],w[21];
int dfs(int pos,int ss,int s,bool pan,bool si,bool ba,bool g)
{
	if(si&&ba) return 0;
	if(pos==0) return pan;
	if(f[pos][ss][s][pan][si][ba][g]!=-1) return f[pos][ss][s][pan][si][ba][g];
	int ans=0;
	int lim=(g?w[pos]:9);
	for(int i=0;i<=lim;i++)
	{
		ans+=dfs(pos-1,s,i,pan||(ss==s&&s==i),(si||i==4),(ba||i==8),g&&(i==lim));
	}
	f[pos][ss][s][pan][si][ba][g]=ans;
	return ans;
}
int suan(int x)
{
	memset(f,-1,sizeof(f));
	len=0;
	while(x)
	{
		w[++len]=x%10;
		x/=10;
	}
	if(len<11) return 0;
	int ans=0;
	for(int i=1;i<=w[len];i++)
		ans+=dfs(len-1,0,i,0,i==4,i==8,i==w[len]);
	return ans;
}
signed main()
{
	int l,r;
	cin>>l>>r;
	cout<<suan(r)-suan(l-1);
	return 0;
}

全源最短路

我们新建一个虚拟节点(在这里我们就设它的编号为 0 )。从这个点向其他所有点连一条边权为 0 的边。

接下来用 Bellman-Ford 算法求出从 0 号点到其他所有点的最短路,记为 h[i] 。

跑一边 SPFA 将所有边的边权设置为 \(w+h[u]−h[v]\),然后跑 dij。

后缀自动机

例题题意小补充:t 为 1 表示不同位置的相同子串算作多个。

struct xxx
{
	int tr[QAQ][31],fa[QAQ],cnt,last;
	ll len[QAQ],ci[QAQ],f[QAQ];
	void init() {cnt=1,last=1;}
	void add(int x)
	{
		int p=last,np=++cnt,q,nq;last=np;
		len[np]=len[p]+1,ci[np]=f[np]=1;
		for(;p&&!tr[p][x];p=fa[p]) tr[p][x]=np;
		if(!p) fa[np]=1;
		else
		{
			q=tr[p][x];
			if(len[q]==len[p]+1) fa[np]=q;
			else
			{
				nq=++cnt;
				for(int i=0;i<26;i++) tr[nq][i]=tr[q][i];
				fa[nq]=fa[q],len[nq]=len[p]+1,fa[q]=fa[np]=nq;
				for(;p&&tr[p][x]==q;p=fa[p]) tr[p][x]=nq;
			}
		}
	}
	void dfs1(int x)
	{
		for(int i=0;i<(int)dian[x].size();i++) dfs1(dian[x][i]),ci[x]+=ci[dian[x][i]];
		f[x]=ci[x];
	}
	ll dfs2(int x)
	{
		if(vis[x]) return f[x];vis[x]=1;
		for(int i=0;i<26;i++) if(tr[x][i]!=0) f[x]+=dfs2(tr[x][i]);
		return f[x];
	}
	void cha(ll x,ll k)
	{
		if(k<=ci[x]) return ;///////////////////////
		k-=ci[x];
		for(int i=0;i<26;i++)
		{
			ll v=tr[x][i];
			if(k>f[v]) k-=f[v];
			else return cout<<(char)('a'+i),cha(v,k),void();
		}
	}
	void gowork()
	{
		init();
		for(int i=0;i<(int)s.size();i++) add(s[i]-'a');
		cin>>t>>k;
		for(int i=1;i<=cnt;i++) dian[fa[i]].push_back(i);
		if(t) dfs1(1);
		else for(int i=1;i<=cnt;i++) f[i]=ci[i]=1;
		f[1]=ci[1]=0,dfs2(1);
		if(k>f[1]) return puts("-1"),void();
		cha(1,k);
	}
} qwp;

dinic

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int QAQ=1e4+7,inf=(2e15+7);
int n,m,s,t,cnt=1,head[510000],kai[510000];
struct xxx {int to,nex,w;} e[QAQ];
void add(int x,int y,int c)
{
	e[++cnt].to=y;
	e[cnt].w=c;
	e[cnt].nex=head[x];
	head[x]=cnt;
	e[++cnt].to=x;
	e[cnt].w=0;
	e[cnt].nex=head[y];
	head[y]=cnt;
}
int dis[510000],da;
bool bfs()
{
	for(int i=1;i<=n;i++) dis[i]=inf;
	queue<int> dui;
	dui.push(s);dis[s]=0;
	kai[s]=head[s];
	while(!dui.empty())
	{
		int x=dui.front();dui.pop();
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].to;
			if(e[i].w>0&&dis[v]==inf)
			{
				dui.push(v),kai[v]=head[v],dis[v]=dis[x]+1;
			}
		}
	}
	if(dis[t]!=inf) return 1;
	return 0;
}
int dfs(int x,int xian)
{
	if(x==t) return xian;
	int k,liu=0;
	for(int i=kai[x];i&&xian>0;i=e[i].nex)
	{
		kai[x]=i;
		int v=e[i].to;
		if(e[i].w>0&&(dis[v]==dis[x]+1))
		{
			k=dfs(v,min(xian,e[i].w));
			if(k==0) dis[v]=inf;
			e[i].w-=k,e[i^1].w+=k;
			liu+=k,xian-=k;
		}
	}
	return liu;
}
signed main()
{
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w;i<=m;i++) cin>>u>>v>>w,add(u,v,w);
	while(bfs()) da+=dfs(s,inf);
	cout<<da;
	return 0;
}

费用流(EA)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int QAQ=3e5+7,inf=2e13;
int n,m,s,t,head[QAQ],cnt=1;
struct xxx {int nex,to,w,c;} e[QAQ];
void add(int x,int y,int w,int c)
{
	e[++cnt]={head[x],y,w,c};
	head[x]=cnt;
	e[++cnt]={head[y],x,0,-c};
	head[y]=cnt;
}

int da1,da2,dis[QAQ],f[QAQ],from[QAQ];
queue<int> dui;
bitset<QAQ> vis;
bool spfa()
{
	while(!dui.empty()) dui.pop();
	for(int i=0;i<=n*2;i++) f[i]=inf,vis[i]=0;
	dui.push(s);
	f[s]=0;
	vis[s]=1;
	dis[s]=inf;
	while(!dui.empty())
	{
		int x=dui.front();dui.pop();
		vis[x]=0;
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].to,w=e[i].w,c=e[i].c;
			if(f[v]>f[x]+c&&w>0)
			{
				f[v]=f[x]+c;
				dis[v]=min(dis[x],w);
				from[v]=i;
				if(vis[v]) continue;
				dui.push(v);
				vis[v]=1;
			}
		}
	}
	if(f[t]<1e10) return 1;
	return 0;
}
void geng()
{
	int x=t,p;
	while(x!=s) p=from[x],e[p].w-=dis[t],e[p^1].w+=dis[t],da2+=dis[t]*e[p].c,x=e[p^1].to;
	da1+=dis[t];
}
signed main()
{
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w,c;i<=m;i++)
	{
		cin>>u>>v>>w>>c; 
		add(u,v,w,c);
	}
	while(spfa()) geng();
	cout<<da1<<" "<<da2;
	return 0;
}

模拟退火

#include<bits/stdc++.h>
using namespace std;
double kai=10000,eps=1,jiang=0.92,fw;//fw 记得赋值 
mt19937 rd(time(0));
#define bu t*(rd()%(2*(int)fw)*1.0-fw)
#define gl 1.0*rand()/RAND_MAX
int ans,sx;//题目要求时开 double 
int cha(int x)
{
	/*
	
	*/
	return ans;
}
signed main()
{
	srand(20090918);
	sx=;//
	fw=;//
	ans=cha(sx);
	while (1.0*clock()/CLOCKS_PER_SEC<0.9)
	{
		int nw=ans,x=sx;
		for(double t=kai;t>eps;t*=jiang)
		{
			int o1=x+bu,k;
			while(o1∈[?,?]) o1=x+bu;
			k=cha(o1);
			if(k>ans) ans=k,sx=o1;
			if(k>nw||exp((k-nw)/t)>gl) x=o1;
		}
	}
	cout<<ans;
	return 0;
}

模拟退火不能无脑退火,要结合性质。

  1. 构造好初始解
  2. 猜想答案特性
  3. 选择更牛的随机下一步的方式
  4. 优化 calc
  5. 调参。

答案数组最好开 double,不开的话一定要记得在 \(△d/t\) 时加上 1.0* 不然你就会完了!

下面是数学的领域

atan2(△y,△x) :极角

acos(-1):π

cos()、sin():。

__builtin_popcount(x)、__builtin_popcountll(x):1 的个数

两直线交点

设两直线方程分别为:
\(l_1=P+t\)v
\(l_2=Q+t\)w

\(t=[(P−Q)×\)w\(]/(\)w\(×\)v\()\)

三点定圆

void ding(xxx o1,xxx o2,xxx o3)
{
	double 
	a1=o2.x-o1.x,a2=o3.x-o1.x,
	b1=o2.y-o1.y,b2=o3.y-o1.y,
	c1=(o2.x*o2.x-o1.x*o1.x+o2.y*o2.y-o1.y*o1.y)/2,
	c2=(o3.x*o3.x-o1.x*o1.x+o3.y*o3.y-o1.y*o1.y)/2;
	o={(b2*c1-b1*c2)/(b2*a1-b1*a2),(a2*c1-a1*c2)/(a2*b1-a1*b2)};
	r=dis(o,o1)+eps;
}

叉积求面积

\(S_{△}=\frac{a×b}{2}\)

切比雪夫距离与曼哈顿距离

曼哈顿 \((x,y) = (x+y,x-y)\) 的切比雪夫
切比雪夫 \((x,y) = ((x+y)/2,(x-y)/2)\) 的曼哈顿

累加公式

平方:\(n(n+1)(2n+1)/6\)
立方:\([n(n+1)/2]^2\)
证明是数形结合旋转三角/

插板法

把 n 个苹果分给 m 个人:
\(C_{m+n-1}^{n-1}\)

log

log(a):以 e 为底
log2(a):以 2 为底
log(a)/log(b):以 b 为底
__lg():以 2 为底,int 类型

1. 旋转坐标系

公式

  • 绕原点旋转‌:
    逆时针旋转θ角度时:
    \(x′=xcos⁡θ−ysin⁡θ\)
    \(y′=xsin⁡θ+ycos⁡θ\)

逆时针旋转 θ 度矩阵:

cos(θ) sin(θ)
-sin(θ) cos(θ)
  • 绕任意点 \((a,b)\) 旋转‌:
    分三步实现:平移坐标系使旋转中心到原点→应用绕原点旋转公式→反向平移。公式为:
    \(x′=(x−a)cos⁡θ−(y−b)sin⁡θ+a\)
    \(y′=(x−a)sin⁡θ+(y−b)cos⁡θ+b\)

二维凸包

先找 \(y\) 最小的那个点,用 atan2(△y,△x) 极角排序其余点,然后维护栈,如果栈顶两个点的直线与当前点与栈顶点的直线叉积 \(<0\),那么弹栈,最后再插入一下最开始那个点就是凸包了。

\(a×b=x_a×y_b-y_a×x_b\)

\(a×b<0\) 则 b 是 a 顺时针旋转。
\(a×b>0\) 则 b 是 a 逆时针旋转。

细节:
cmp1 若 y 等则按 x 排。
cmp2 若 val 等则按 y 排。
怎么排无所谓。

数论分块

\(\%\) 拆为下取整除法。
\(l\) 所在块的右端点为 \(k/(k/l)\)
\(l=r+1\)

6. 半平面交

小言

逆转叉积正。
一个直线我们只取它左边。

流程

极角排序所有直线,如果极角相同优先靠左的直线。
存两个队列——交点队列和直线队列,注意交点队列在运算时总是比直线队列短 \(1\)
遍历所有直线,如果两个直线极角一样(差 eps)那么不重复计算,在交点队列弹掉所有在当前直线右边的点。
把当前直线加入直线队列并在交点队列里加上其与直线队列上一个直线的交点。
最后再用直线队列的尾消一下交点队列的头
再拿新直线队列的头消一下交点队列的尾
如果最后直线队列长度小于 \(3\),那么无解。(其实要特判一下只有一点直线的情况,我们可以直接在开始插入四个超级直线解决)
还要记得把开头的直线和末尾的直线的交点加进去,最后所有交点组成的凸包是半平面交。

求面积就选择点 \(1\),从它开始分割很多三角形,用叉积除二求面积即可。

#include<bits/stdc++.h>
using namespace std;
const int QAQ=1010;
const double eps=1e-9,inf=1000;
int n,cnt,ccx;
struct dian {double x,y;} d[QAQ],jd[QAQ],ans[QAQ];
struct bian {dian x,y;double s;} l[QAQ],dui[QAQ];
double cha(dian a,dian b) {return a.x*b.y-a.y*b.x;}
dian operator + (dian a,dian b) {return {a.x+b.x,a.y+b.y};}
dian operator * (dian a,double b) {return {a.x*b,a.y*b};}
dian xl(dian a,dian b) {return {b.x-a.x,b.y-a.y};}
bool you(dian p,bian s) {return cha(xl(s.x,p),xl(s.x,s.y))>0;}
bool cmp1(bian a,bian b) {return (a.s==b.s)?you(b.x,a):a.s<b.s;}
dian jiao(bian a,bian b)
{
	dian o1=xl(a.x,a.y),o2=xl(b.x,b.y),o3=xl(b.x,a.x);
	double cab=cha(o3,o2)/cha(o2,o1);
	return a.x+o1*cab;
}
void work()
{
	for(int i=1;i<=cnt;i++)
		l[i].s=atan2(l[i].y.y-l[i].x.y,l[i].y.x-l[i].x.x);
	sort(l+1,l+cnt+1,cmp1);
	int zb=1,yb=0;
	dui[++yb]=l[1];
	for(int i=2;i<=cnt;i++)
	{
		if(fabs(l[i].s-l[i-1].s)<eps) continue;
		while(zb<yb&&you(jd[yb-1],l[i])) yb--;
		while(zb<yb&&you(jd[zb],l[i])) zb++;
		dui[++yb]=l[i];
		if(zb<yb) jd[yb-1]=jiao(dui[yb],dui[yb-1]);
	}
	while(zb<yb&&you(jd[yb-1],dui[zb])) yb--;
	while(zb<yb&&you(jd[zb],dui[yb])) zb++;
	if(yb-zb+1<=2) return ;
	jd[yb]=jiao(dui[zb],dui[yb]);
	for(int i=zb;i<=yb;i++) ans[++ccx]=jd[i];
}
signed main()
{
	cin>>n;
	for(int i=1,m;i<=n;i++)
	{
		cin>>m;
		for(int j=1;j<=m;j++) cin>>d[j].x>>d[j].y;
		for(int j=1;j<m;j++) l[++cnt]={d[j],d[j+1]};
		l[++cnt]={d[m],d[1]};
	}
	dian a={-inf,inf},b={inf,inf},c={-inf,-inf},d={inf,-inf};
	l[++cnt]={a,c},l[++cnt]={c,d},l[++cnt]={d,b},l[++cnt]={b,a};
	work();
	double da=0;
	for(int i=2;i<ccx;i++) da+=cha(xl(ans[1],ans[i]),xl(ans[1],ans[i+1]));
	printf("%.3f",da/2);
	return 0;
}
posted @ 2025-10-18 09:50  _a1a2a3a4a5  阅读(9)  评论(0)    收藏  举报