zoukankan      html  css  js  c++  java
  • HNOI2016 矿区

    矿区

    平面上的矿区划分成了若干个开发区域。

    简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点的线段组成。每个开发区域的矿量与该开发区域的面积有关:具体而言,面积为(s)的开发区域的矿量为(s^2)

    现在有(m)个开采计划。每个开采计划都指定了一个由若干开发区域组成的多边形,一个开采计划的优先度被规定为矿量的总和÷开发区域的面积和;例如,若某开采计划指定两个开发区域,面积分别为(a)(b),则优先度为((a^2+b^2)/(a+b))。由于平面图是按照划分开发区域边界的点和边给出的,因此每个开采计划也只说明了其指定多边形的边界,并未详细指明是哪些开发区域(但很明显,只要给出了多边形的边界就可以求出是些开发区域)。

    你的任务是求出每个开采计划的优先度。为了避免精度问题,你的答案必须按照分数的格式输出,即求出分子和分母,且必须是最简形式(分子和分母都为整数,而且都消除了最大公约数;

    由于某些原因,你必须依次对每个开采计划求解(即下一个开采计划会按一定格式加密,加密的方式与上一个开采计划的答案有关)。具体的加密方式见输入格式。

    对于 $ 100 % $ 的数据,$ n, k leq 2 imes 10^5, m leq 3n-6, |x_i|, |y_i| leq 3×10^4$。所有开采计划的 $ d $ 之和不超过 (2 imes 10^6)。保证任何开采计划都包含至少一个开发区域,且这些开发区域构成一个连通块。保证所有开发区域的矿量和不超过 $ 2^{63}-1 $。保证平面图中没有多余的点和边。保证数据合法。由于输入数据量较大,建议使用读入优化。

    题解

    https://www.cnblogs.com/heyujun/p/10447472.html

    先平面图转对偶图,

    建好了对偶图之后随意拿出一个生成树,以无边界的范围为根。

    无边界的范围很好求,用叉积算出有向面积时,算出来是负数的就是无边界的范围。

    然后标记所有的树边,记录生成树中每个子树的矿区面积和及面积平方和。

    对于每一个询问,先找到询问里出现的边,如果有非树边就忽略,否则如果这条边所在的面是儿子,就加上子树的面积,如果是父亲就减去儿子子树的面积。

    这个可以通过画图手玩进行证明。

    struct point {int64 x,y;};
    
    IN point operator-(CO point&a,CO point&b){
    	return {a.x-b.x,a.y-b.y};
    }
    IN int64 cross(CO point&a,CO point&b){
    	return a.x*b.y-a.y*b.x;
    }
    IN float128 angle(CO point&a,CO point&b){
    	return atan2((float128)b.y-a.y,b.x-a.x);
    }
    
    struct edge {int u,v;};
    
    CO int N=2e6+10;
    point p[N];
    edge e[N];
    map<pair<int,int>,int> loc;
    float128 ang[N];
    vector<int> to[N];
    int nxt[N],adj[N];
    array<int64,2> sum[N];
    
    IN array<int64,2> operator+(CO array<int64,2>&a,CO array<int64,2>&b){
    	return {a[0]+b[0],a[1]+b[1]};
    }
    IN array<int64,2> operator-(CO array<int64,2>&a,CO array<int64,2>&b){
    	return {a[0]-b[0],a[1]-b[1]};
    }
    
    edge e2[N];
    vector<int> to2[N];
    int fa[N],vis[N],tree[N];
    
    void dfs(int u){
    	vis[u]=1;
    	for(int i:to2[u]){
    		int v=e2[i].v;
    		if(vis[v]) continue;
    		tree[i]=tree[i^1]=1;
    //		cerr<<"tree "<<u<<" "<<v<<endl;
    		fa[v]=u,dfs(v);
    		sum[u]=sum[u]+sum[v];
    	}
    }
    int main(){
    	int n=read<int>(),m=read<int>(),Q=read<int>();
    	for(int i=1;i<=n;++i) read(p[i].x),read(p[i].y);
    	for(int i=1;i<=m;++i){
    		int u=read<int>(),v=read<int>();
    		e[i<<1]={u,v},ang[i<<1]=angle(p[u],p[v]),to[u].push_back(i<<1);
    		e[i<<1|1]={v,u},ang[i<<1|1]=angle(p[v],p[u]),to[v].push_back(i<<1|1);
    		loc[{u,v}]=i<<1,loc[{v,u}]=i<<1|1;
    	}
    	for(int i=1;i<=n;++i){
    		sort(to[i].begin(),to[i].end(),[&](int a,int b)->bool{
    			return ang[a]<ang[b];
    		});
    		for(int j=0;j<(int)to[i].size();++j)
    			nxt[to[i][j]^1]=to[i][(j+to[i].size()-1)%to[i].size()];
    	}
    	int idx=0,root=-1;
    	for(int i=2;i<=2*m+1;++i)if(!adj[i]){
    		adj[i]=++idx;
    //		cerr<<idx<<" face="<<endl;
    //		cerr<<" ("<<p[e[i].u].x<<","<<p[e[i].u].y<<") -> ("<<p[e[i].v].x<<","<<p[e[i].v].y<<")"<<endl;
    		int64 area=0;
    		point st=p[e[i].u];
    		for(int j=nxt[i];j!=i;j=nxt[j]){
    			adj[j]=idx;
    //			cerr<<" ("<<p[e[j].u].x<<","<<p[e[j].u].y<<") -> ("<<p[e[j].v].x<<","<<p[e[j].v].y<<")"<<endl;
    			area+=cross(p[e[j].u]-st,p[e[j].v]-st);
    		}
    		if(area<0) root=idx;
    		else sum[idx]={area*area,2*area}; // 4 times
    	}
    	
    	for(int i=2;i<=2*m+1;++i){
    		e2[i]={adj[i],adj[i^1]};
    		to2[adj[i]].push_back(i);
    	}
    	dfs(root);
    	array<int64,2> ans={};
    	while(Q--){
    		static int q[N];
    		int c=(read<int64>()+ans[0])%n+1;
    		for(int i=1;i<=c;++i) q[i]=(read<int64>()+ans[0])%n+1;
    		q[c+1]=q[1];
    		ans={0,0};
    		for(int i=1;i<=c;++i){
    			int id=loc[{q[i],q[i+1]}];
    			if(!tree[id]) continue;
    			int u=adj[id],v=adj[id^1];
    //			cerr<<"side "<<u<<" "<<v<<endl;
    			if(fa[u]==v) ans=ans+sum[u];
    			else if(fa[v]==u) ans=ans-sum[v];
    		}
    		int64 g=gcd(ans[0],ans[1]);
    		ans[0]/=g,ans[1]/=g;
    		printf("%lld %lld
    ",ans[0],ans[1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    计算机操作系统 存储器管理
    数据结构 平衡二叉树avl c++
    数据结构 线索二叉树 c++
    数据结构 赫夫曼树及其应用 c++
    c++ cstring 常用函数
    数据结构 哈希表 c++
    数据结构 静态链表
    ajax返回填充的数据不显示
    使用JSON.parse()转化成json对象需要注意的地方
    参数错误导致bug
  • 原文地址:https://www.cnblogs.com/autoint/p/12782372.html
Copyright © 2011-2022 走看看