7 条题解

  • 1
    @ 2025-3-31 21:03:14

    题解

    思路

    直接计算连通块数量难度较大,由平面图性质利用欧拉公式 V−E+F=C(F 为有界面数量)转换成计算点数、边数、面数。如果一个点被 t 个环包围,那么仅在 ( z t ​ ) 种情况下这个点出现在 z 个环的交集中,所以它对答案的贡献为 ( z t ​ )。边、面的情况同理。所以只需要对于每个点、边、面统计有多少个环包含它。

    与 std 不同,这里用同一种方法统计点、边、面的贡献。

    对于统计每个面的贡献,建出平面图的对偶图,再以无界面的点为根随便建一颗生成树。脑补一下图:一棵树树枝插进一个环里。如何快速给环覆盖上的每个节点都加 1 呢?当树枝进入环时,即节点 u 在环内,fa u ​ 在环外时,给 u 子树节点都加 1;在树枝出环时,即 fa u ​ 在环内,u 在环外时,给 u 子树减 1。

    如何统计点和边的贡献?回到原图,如果一个面被环包含,那么所有面上的点也被环包含。所以可以再最后把每个面的贡献加到点上,这样每个点 u 都会被统计 d u ​ (d u ​ 为点 u 的度数,也是与 u 相邻的面的个数)次,最后再除掉;但是还没结束,那些恰好在环上的点冰不会被统计恰好 d u ​ 次,因为每次只有环内的面的贡献加到了这些点上。但注意到这些点加起来也不会超过 10 5 个,于是处理环时对于每个环上点把贡献补成 d u ​ 就好了(加上环外相邻面的数量),这样最后除掉就是对的。边同理。

    不用平衡树自然是最优解。

    Code

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cassert>
    #define PII pair<int,int>
    #define x first
    #define y second
    
    typedef long long ll;
    
    using namespace std;
    
    PII operator-(const PII& u,const PII& v)
    {
    	return {u.x-v.x,u.y-v.y};
    }
    
    ll operator*(const PII& u,const PII& v)
    {
    	return 1LL*u.x*v.y-1LL*u.y*v.x;
    }
    
    int qt(const PII& u)
    {
    	if(u.x>0&&u.y>=0) return 1;
    	if(u.y>0&&u.x<=0) return 2;
    	if(u.x<0&&u.y<=0) return 3;
    	if(u.y<0&&u.x>=0) return 4;
    	return 0;
    }
    
    bool operator<(const PII& u,const PII& v)
    {
    	int i=qt(u),j=qt(v);
    	return i==j? u*v>0:i<j;
    }
    
    const int N=1e5+10,M=N*6,mod=998244353;
    
    int n,m,k,cnt,idx;
    PII p[N];
    struct edge
    {
    	int from,to,id,val;
    }eg[M<<1];
    vector<edge> G[N];
    void add_edge(int u,int v)
    {
    	eg[cnt]={u,v,cnt,0};
    	G[u].push_back(eg[cnt]);
    	cnt++;
    }
    bool operator<(const edge& u,const edge& v)
    {
    	return p[u.to]-p[u.from]<p[v.to]-p[v.from];
    }
    
    int root,fa[M];
    ll tag[M][3];
    vector<int> T[M];
    bool vis[M];
    
    void dfs(int u)
    {
    	vis[u]=true;
    	for(int v:T[u])
    	{
    		if(vis[v]) continue;
    		fa[v]=u;
    		tag[v][2]+=tag[u][2];
    		dfs(v);
    	}
    }
    
    int st[N],tp;
    int stk[M],top;
    bool ins[M];
    
    ll ksm(ll x,ll y)
    {
    	ll res=1;
    	while(y)
    	{
    		if(y&1) res=res*x%mod;
    		y>>=1;
    		x=x*x%mod;
    	}
    	return res;
    }
    ll fac[N],inv[N];
    
    ll C(int x,int y)
    {
    	if(x<y) return 0;
    	return fac[x]*inv[y]%mod*inv[x-y]%mod;
    }
    
    int main()
    {
    	fac[0]=1;
    	for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;
    	inv[N-1]=ksm(fac[N-1],mod-2);
    	for(int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    	ios::sync_with_stdio(false);
    	cin>>n>>m>>k;
    	for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
    	for(int i=1;i<=m;i++)
    	{
    		int u,v;
    		cin>>u>>v;
    		add_edge(u,v),add_edge(v,u);
    	}
    	for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
    
    	for(int i=0;i<cnt;i++)
    	{
    		if(eg[i].val) continue;
    		int now=i;
    		idx++;
    		ll s=0;
    		do
    		{
    			s+=p[eg[now].from]*p[eg[now].to];
    			eg[now].val=idx;
    			int u=eg[now].to;
    			auto it=lower_bound(G[u].begin(),G[u].end(),eg[now^1]);
    			if(it==G[u].begin()) it=G[u].end();
    			it--;
    			now=it->id;
    		}while(now!=i);
    		if(s<0) root=idx;
    	}
    	for(int i=0;i<cnt;i++)
    	{
    		int u=eg[i].val,v=eg[i^1].val;
    		T[u].push_back(v);
    	}
    	dfs(root);
    	
    	for(int o=1;o<=k;o++)
    	{
    		cin>>tp;
    		for(int i=0;i<tp;i++) cin>>st[i];
    		ll s=0;
    		for(int i=0;i<tp;i++) s+=p[st[i]]*p[st[(i+1)%tp]];
    		if(s<0) reverse(st,st+tp);
    		for(int i=0;i<tp;i++)
    		{
    			int u=st[i],v=st[(i+1)%tp];
    			auto it=lower_bound(G[u].begin(),G[u].end(),(edge){u,v,0,0});
    			int in=eg[it->id].val,out=eg[it->id^1].val;
    			tag[it->id^1][1]++;
    			if(!ins[in]&&fa[in]==out) tag[in][2]++,ins[stk[++top]=in]=true;
    			else if(!ins[out]&&fa[out]==in) tag[out][2]--,ins[stk[++top]=out]=true;
    		}
    		while(top) ins[stk[top--]]=false;
    		for(int i=0;i<tp;i++)
    		{
    			int l=st[(i-1+tp)%tp],mid=st[i],r=st[(i+1)%tp];
    			auto it1=lower_bound(G[mid].begin(),G[mid].end(),(edge){mid,l,0,0}),
    				 it2=lower_bound(G[mid].begin(),G[mid].end(),(edge){mid,r,0,0});
    			int tot=G[mid].size();
    			tag[mid][0]+=(it2-it1+tot)%tot;
    		}
    	}
    	memset(vis,0,sizeof vis);
    	dfs(root);
    	for(int i=0;i<cnt;i++)
    	{
    		int u=eg[i].from,in=eg[i].val;
    		tag[u][0]+=tag[in][2];
    		tag[i][1]+=tag[in][2];
    	}
    	for(int i=1;i<=n;i++) tag[i][0]/=G[i].size();
    	
    	int q;
    	cin>>q;
    	while(q--)
    	{
    		int z;
    		cin>>z;
    		ll ans=0;
    		for(int i=1;i<=n;i++) ans=(ans+C(tag[i][0],z))%mod;
    		for(int i=0;i<cnt;i+=2) ans=(ans-C(tag[i][1],z))%mod;
    		for(int i=1;i<=idx;i++) ans=(ans+C(tag[i][2],z))%mod;
    		cout<<(ans+mod)%mod<<'\n';
    	}
    	
    	return 0;
    }
    
    • @ 2025-3-31 21:04:01

      喵呜,点个赞再走~~~

信息

ID
12
时间
3000ms
内存
512MiB
难度
10
标签
递交数
42
已通过
5
上传者