zoukankan      html  css  js  c++  java
  • JZOJ6681. 【2020.06.02省选模拟】图

    Description

    • 给定一张无重边、自环、割点的平面图,你需要回答 Q 次询问,每次询问会给出一个简单环,你需要回答在由这个简单环围成的多边形内部(包括边界上)的点有多少个。
    • 保证图中每条线段不会通过除这条线段端点以外的其他点。
    • 询问按照顺时针或逆时针给出。
      n<=1e5,m<=3e5n<=1e5,m<=3e5
      source:CF223E

    Solution

    • 由于这是一个平面图,什么特殊的样子都没有,非常的优美,所以也有一个优美的结论:
    • 任意造一个生成树,树根为汇点,每一个点有1点初始流量流向它的父亲(有向边),每条边有sz[x]的流量流过。
    • 一个多边形内的点数就是所有边界上的点,入边不在多边形内的流量,与出边不在多边形内的流量之差。
    • 感性理解,非常正确,一些边进来,又流出去,多出的流量就是这个多边形内新产生的,即点数。
    • 那么只需要极角排序加二分前缀和就可以算出不在多边形内的入边(这显然是一个区间)的流量之和了。
    • PS:判顺时针逆时针用叉积算面积。
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define maxn 300005
    #define ll long long
    #define db double  
    using namespace std;
    
    const db Pi=acos(-1.0);
    int n,m,i,j,k,Q,q[maxn];
    struct dot{
    	int x,y;
    	dot(int _x=0,int _y=0){x=_x,y=_y;}
    } p[maxn];
    dot operator-(dot a,dot b){return dot(a.x-b.x,a.y-b.y);}
    ll operator*(dot a,dot b){return (ll)a.x*b.y-(ll)a.y*b.x;}
    struct vec{
    	dot x; int id; db r;
    	vec(dot _x=0,int _id=0){x=_x,id=_id,r=atan2(x.y,x.x);r+=(r<0)?2*Pi:0;}
    };
    vector<vec> E[maxn],e[maxn];
    vector<ll> s[maxn];
    int cmp(vec a,vec b){return a.r<b.r;}
    
    void read(int &x){
    	x=0; char ch=getchar(); int tp=1;
    	for(;(ch<'0'||ch>'9')&&(ch!='-');ch=getchar());
    	if (ch=='-') tp=-1,ch=getchar();
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	x=x*tp;
    }
    
    int bz[maxn],sz[maxn],fa[maxn],d[maxn];
    void BFS(int st){
    	int t=0,w=1; d[1]=st,bz[st]=1;
    	while (t<w){
    		int x=d[++t];
    		for(int i=0;i<E[x].size();i++) if (!bz[E[x][i].id]){
    			e[x].push_back(E[x][i]),bz[E[x][i].id]=1;
    			fa[E[x][i].id]=x,d[++w]=E[x][i].id;
    		}
    	}
    	for(i=w;i>=1;i--) sz[d[i]]++,sz[fa[d[i]]]+=sz[d[i]];
    }
    
    int main(){
    //	freopen("graph.in","r",stdin);
    //	freopen("graph.out","w",stdout);
    	read(n),read(m);
    	for(i=1;i<=m;i++) {
    		read(j),read(k);
    		E[j].push_back(vec(0,k));
    		E[k].push_back(vec(0,j));
    	}
    	for(i=1;i<=n;i++) read(p[i].x),read(p[i].y);
    	for(i=1;i<=n;i++){
    		for(j=0;j<E[i].size();j++) 
    			E[i][j]=vec(p[E[i][j].id]-p[i],E[i][j].id);
    		sort(E[i].begin(),E[i].end(),cmp);
    	}
    	p[0]=dot(-1e9-1,-1e9-1);
    	int id=1; for(i=2;i<=n;i++) if (p[i].x<p[id].x) id=i;
    	BFS(id);
    	for(i=1;i<=n;i++){
    		s[i].push_back(0);
    		for(j=0;j<e[i].size();j++)
    			s[i].push_back(s[i][s[i].size()-1]+sz[e[i][j].id]);
    	}
    	read(Q); int K; ll sq,ans;
    	while (Q--){
    		read(K);for(i=1;i<=K;i++) read(q[i]);
    		for(sq=0,i=1;i<=K;i++) sq+=p[q[i]]*p[q[i%K+1]];
    		if (sq<0) for(i=1;i<=K/2;i++) swap(q[i],q[K-i+1]);
    		ans=0;
    		for(i=1;i<=K;i++){ 
    			int x=q[i],nex=q[i%K+1],pre=q[(i-1+K-1)%K+1];
    			dot v1=p[nex]-p[x],v2=p[pre]-p[x];
    			db r1=atan2(v1.y,v1.x),r2=atan2(v2.y,v2.x);
    			dot v3=p[fa[x]]-p[x]; db r3=atan2(v3.y,v3.x);
    			if (r1<0) r1+=2*Pi; if (r2<0) r2+=2*Pi; if (r3<0) r3+=2*Pi;
    			
    			if (r2<r1) { if (r2<r3&&r3<r1) ans+=sz[x]; } else 
    				if (r3>r2||r3<r1) ans+=sz[x];
    			int l=0,r=e[x].size()-1,mid,id1=-1,id2=-1;
    			while (l<=r){
    				int mid=(l+r)>>1;
    				if (e[x][mid].r<r1) id1=mid,l=mid+1;
    				else r=mid-1;
    			}
    			l=0,r=e[x].size()-1;
    			while (l<=r){
    				int mid=(l+r)>>1;
    				if (e[x][mid].r<=r2) id2=mid,l=mid+1;
    				else r=mid-1;
    			}
    			if (r2<r1) ans-=s[x][id1+1]-s[x][id2+1]; else 
    				ans-=s[x][id1+1]+s[x][s[x].size()-1]-s[x][id2+1];
    		}
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    四大组件之内容提供者
    【风马一族_代码英语】英语学习
    利用Maven快速创建一个简单的spring boot 实例
    Maven项目下面没有src/main/java这个包
    Maven中,pom.xml文件报错
    Maven一:maven的下载和环境安装以及创建简单的Maven项目
    SpringMVC
    自动装箱、拆箱
    序列化:Serializable
    java反射机制出浅读
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090878.html
Copyright © 2011-2022 走看看