NC20474. [ZJOI2008]RISK
描述
输入描述
输入文件的第一行中包括两个整数n,m。分别表示地图上的国家数和描述国家的边界的线段的数量。1 ≤ n ≤ 600,1 ≤ m ≤ 4000。接下来n行,每行用一对数描述了某个国家的主力军队的坐标。接下来m行,每行有4个数x1,y1,x2,y2,(x1,y1)-(x2,y2)描述了一条国界线。所有点的坐标都是0-10000之间的整数。保证输入的所有线段至多只会在线段交点处相交。整张地图上有且仅有一块面积无限的空白区域不属于任何国家。每一条国界线两侧的区域或者隶属于两个不同的国家,或者分隔了一个国家与那块无穷大的空白区域。即保证一条国界线两侧的区域不同时属于同一个国家或是同时都是空白区域。所有封闭区域内部包含且仅包含一支主力军队,表示了该区域的归属。例如上图中第一行的数据是合法的。而第二行中的数据都是不合法的。左边的那幅图包含线段两侧都是空白区域;中间的图包含线段两侧区域同时属于同一个国家;右边的图中军队被布置在了国界线上,因此非法;此外若最右侧的图中若没有军队也是非法的。保证输入文件提供的数据都是合法的,你的程序不需要进行数据合法性的判定。
输出描述
包括n行,每行第一个数字x表示有x个国家可能与这个国家交战,接着在同一行中升序输出x个整数,表示可能与这个国家交战的国家的编号。
国家按输入中给出的顺序从1到n编号。注意数字间严格以一个空格隔开,并且不要在行末输出多余的空白字符。
示例1
输入:
4 12 3 2 11 8 12 17 1 19 0 0 10 0 10 0 20 0 20 0 20 10 20 10 20 20 20 20 10 20 10 20 0 20 0 20 0 10 0 10 0 0 10 0 10 10 0 10 10 10 20 10 10 10 10 20 10 10
输出:
2 2 4 2 1 3 2 2 4 2 1 3
C++ 解法, 执行用时: 13ms, 内存消耗: 4992K, 提交时间: 2022-07-23 00:13:30
#include<bits/stdc++.h> using namespace std; inline int read(){ char ch=getchar();int i=0,f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();} return i*f; } inline void W(int x){ static int buf[50]; if(!x){putchar('0');return;} if(x<0){putchar('-');x=-x;} while(x)buf[++buf[0]]=x%10,x/=10; while(buf[0])putchar(buf[buf[0]--]+'0'); } const int Maxn=1e4+50; const double PI=acos(-1.0); const double eps=1e-9; inline int sgn(double x){return (int)(x>eps)-(x<-eps);} struct P{ int x,y; P(){} P(int x,int y):x(x),y(y){} friend inline P operator -(const P &a,const P &b){return P(a.x-b.x,a.y-b.y);} friend inline int operator *(const P &a,const P &b){return a.x*b.y-a.y*b.x;} inline double slope(){return atan2(y,x);} }p[Maxn]; struct E{ int a,b; E(){} E(int a,int b):a(a),b(b){} }e[Maxn]; int n,m,a[Maxn],tot,g[Maxn],v[Maxn],nt[Maxn],ec=1,bl[Maxn],bl_p[Maxn],Pcnt; inline void add(int x,int y){nt[++ec]=g[x];g[x]=ec;v[ec]=y;} map< int,int >S_p[Maxn<<1]; inline int getid(int x,int y){ x+=10000; if(S_p[x].count(y))return S_p[x][y]; else return (S_p[x].insert(make_pair(y,++tot)),p[tot]=P(x-10000,y),tot); } namespace Area{ int vis[Maxn]; struct cmp{ inline bool operator ()(const pair<double,int> &a,const pair<double,int> &b){ int t=sgn(a.first-b.first); return (t<0)||(t==0&&a.second<b.second); } }; set< pair<double,int>,cmp >S_l[Maxn]; int st[Maxn],top; inline int area(){ int res=0; for(int i=1;i<=top;i++)res+=p[v[st[i]^1]]*p[v[st[i]]]; return res; } inline int getsuf(int now){ double ang=(p[v[now]]-p[v[now^1]]).slope(); int t=v[now]; set< pair<double,int> >::iterator suf=S_l[t].lower_bound(make_pair((ang<=0)?ang+PI:ang-PI,0)); if(suf==S_l[t].begin())return (*--S_l[t].end()).second; return (*--suf).second; } inline void dfs(int x){ vis[x]=1;st[++top]=x; int suf=getsuf(x); if(vis[suf]){ int ar=area(); int nowP=(ar>0?++Pcnt:0); for(int i=1;i<=top;i++)bl[st[i]]=nowP; for(;top>=1;--top){ int a=v[st[top]^1],b=v[st[top]]; S_l[a].erase(S_l[a].lower_bound(make_pair((p[b]-p[a]).slope(),st[top]))); } }else dfs(suf); } inline void getarea(){ for(int i=1;i<=tot;i++){ for(int j=g[i];j;j=nt[j]) S_l[i].insert(make_pair((p[v[j]]-p[i]).slope(),j)); } for(int i=2;i<=ec;i++) if(!vis[i])dfs(i); } } namespace Scanline{ int vis[Maxn],tp,tcnt; struct T{ int a,b,u,id; T(){} T(int a,int b,int u):a(a),b(b),u(u){} friend inline bool operator <(const T &a,const T &b){ if(a.a==b.a&&a.u!=b.u)return a.u>b.u; else if(a.a==b.a)return (p[a.b]-p[a.a])*(p[b.b]-p[a.a])<0; else if(p[a.a].x!=p[b.a].x)return p[a.a].x<p[b.a].x; else return p[a.a].y>p[b.a].y; } }t[Maxn]; struct cmp{ inline bool operator ()(const T &a,const T &b){ if(a.a==a.b)return (p[b.b]-p[a.a])*(p[b.a]-p[a.a])<0; if(b.a==b.b)return (p[a.b]-p[b.a])*(p[a.a]-p[b.a])>0; int t1=(p[b.b]-p[a.a])*(p[b.a]-p[a.a]),t2=(p[b.b]-p[a.b])*(p[b.a]-p[a.b]); int t3=(p[a.b]-p[b.a])*(p[a.a]-p[b.a]),t4=(p[a.b]-p[b.b])*(p[a.a]-p[b.b]); return (t1<0&&t2<=0)||(t2<0&&t1<=0)||(t3>0&&t4>=0)||(t4>0&&t3>=0); } }; set<T,cmp>S; void dfs(int x){ vis[x]=1;if(p[x].y>p[tp].y)tp=x; for(int j=g[x];j;j=nt[j])if(!vis[v[j]])dfs(v[j]); } inline void connect(){ tcnt=0;S.clear(); for(int i=1,j=tot;i<=j;i++) if(g[i]&&!vis[i]){ dfs(tp=i); t[++tcnt]=T(tp,tp,1); } for(int i=1;i<=tot;i++) for(int j=g[i];j;j=nt[j]) if(p[v[j]].x>p[i].x){ t[++tcnt]=T(i,v[j],0); t[++tcnt]=T(v[j],i,2); } sort(t+1,t+tcnt+1); for(int i=1;i<=tcnt;i++){ if(t[i].u==0)S.insert(t[i]); else if(t[i].u==2)S.erase(S.find(T(t[i].b,t[i].a,0))); else{ set<T>::iterator it=S.lower_bound(t[i]); if(it==S.begin())continue; --it;add(it->a,t[i].a);add(t[i].a,it->a); } } } inline void getarea(){ tcnt=0;S.clear(); for(int i=1;i<=n;i++){ t[++tcnt]=T(a[i],a[i],1); } for(int i=1;i<=tot;i++){ for(int j=g[i];j;j=nt[j]){ if(p[v[j]].x>p[i].x){ t[++tcnt]=T(i,v[j],0); t[tcnt].id=j^1; t[++tcnt]=T(v[j],i,2); } } } sort(t+1,t+tcnt+1); for(int i=1;i<=tcnt;i++){ if(t[i].u==0)S.insert(t[i]); else if(t[i].u==2)S.erase(S.find(T(t[i].b,t[i].a,0))); else{ set<T>::iterator it=S.lower_bound(t[i]); --it;bl_p[t[i].a]=bl[(it)->id]; } } } } bool isadj[Maxn][Maxn]; int main(){ n=read(),m=read(); for(int i=1;i<=n;i++){ int x=read(),y=read(); a[i]=getid(x,y); } for(int i=1;i<=m;i++){ int x=read(),y=read(); e[i].a=getid(x,y); x=read(),y=read(); e[i].b=getid(x,y); add(e[i].a,e[i].b); add(e[i].b,e[i].a); } Scanline::connect(); Area::getarea(); Scanline::getarea(); for(int i=2;i<=ec;i++) if(bl[i]&&bl[i^1]){ isadj[bl[i]][bl[i^1]]=1; } for(int i=1;i<=n;i++){ static int st[Maxn],top; top=0; for(int j=1;j<=n;j++)if(i!=j&&isadj[bl_p[a[i]]][bl_p[a[j]]])st[++top]=j; W(top); for(int j=1;j<=top;j++)putchar(' '),W(st[j]); if(i!=n)putchar('\n'); } }