A最短路 几何
大佬几何模板
求出sum角,
求A,B 角, C角
得直线A-D1 直线B-D2 弧线D1-D2 相加即可
#include
using namespace std; // `计算几何模板` const double eps = 1e-8; const double inf = 1e20; const double pi = acos(-1.0); const int maxp = 1010; //`Compares a double to zero` int sgn(double x){ if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } //square of a double inline double sqr(double x){return x*x;} struct Point{ double x,y; Point(){} Point(double _x,double _y){ x = _x; y = _y; } void input(){ scanf("%lf%lf",&x,&y); } void output(){ printf("%.2f %.2f\n",x,y); } bool operator == (Point b)const{ return sgn(x-b.x) == 0 && sgn(y-b.y) == 0; } bool operator < (Point b)const{ return sgn(x-b.x)== 0?sgn(y-b.y)<0:x 0)return 2; else return 3; } // 点在线段上的判断 bool pointonseg(Point p){ return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0; } //`两向量平行(对应直线平行或重合)` bool parallel(Line v){ return sgn((e-s)^(v.e-v.s)) == 0; } //`两线段相交判断` //`2 规范相交` //`1 非规范相交` //`0 不相交` int segcrossseg(Line v){ int d1 = sgn((e-s)^(v.s-s)); int d2 = sgn((e-s)^(v.e-s)); int d3 = sgn((v.e-v.s)^(s-v.s)); int d4 = sgn((v.e-v.s)^(e-v.s)); if( (d1^d2)==-2 && (d3^d4)==-2 )return 2; return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) || (d2==0 && sgn((v.e-s)*(v.e-e))<=0) || (d3==0 && sgn((s-v.s)*(s-v.e))<=0) || (d4==0 && sgn((e-v.s)*(e-v.e))<=0); } //`直线和线段相交判断` //`-*this line -v seg` //`2 规范相交` //`1 非规范相交` //`0 不相交` int linecrossseg(Line v){ int d1 = sgn((e-s)^(v.s-s)); int d2 = sgn((e-s)^(v.e-s)); if((d1^d2)==-2) return 2; return (d1==0||d2==0); } //`两直线关系` //`0 平行` //`1 重合` //`2 相交` int linecrossline(Line v){ if((*this).parallel(v)) return v.relation(s)==3; return 2; } //`求两直线的交点` //`要保证两直线不平行或重合` Point crosspoint(Line v){ double a1 = (v.e-v.s)^(s-v.s); double a2 = (v.e-v.s)^(e-v.s); return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1)); } //点到直线的距离 double dispointtoline(Point p){ return fabs((p-s)^(e-s))/length(); } //点到线段的距离 double dispointtoseg(Point p){ if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0) return min(p.distance(s),p.distance(e)); return dispointtoline(p); } //`返回线段到线段的距离` //`前提是两线段不相交,相交距离就是0了` double dissegtoseg(Line v){ return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e))); } //`返回点p在直线上的投影` Point lineprog(Point p){ return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) ); } //`返回点p关于直线的对称点` Point symmetrypoint(Point p){ Point q = lineprog(p); return Point(2*q.x-p.x,2*q.y-p.y); } }; //圆 struct circle{ Point p;//圆心 double r;//半径 circle(){} circle(Point _p,double _r){ p = _p; r = _r; } circle(double x,double y,double _r){ p = Point(x,y); r = _r; } //`三角形的外接圆` //`需要Point的+ / rotate() 以及Line的crosspoint()` //`利用两条边的中垂线得到圆心` //`测试:UVA12304` circle(Point a,Point b,Point c){ Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft())); Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft())); p = u.crosspoint(v); r = p.distance(a); } //`三角形的内切圆` //`参数bool t没有作用,只是为了和上面外接圆函数区别` //`测试:UVA12304` circle(Point a,Point b,Point c,bool t){ Line u,v; double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x); u.s = a; u.e = u.s + Point(cos((n+m)/2),sin((n+m)/2)); v.s = b; m = atan2(a.y-b.y,a.x-b.x) , n = atan2(c.y-b.y,c.x-b.x); v.e = v.s + Point(cos((n+m)/2),sin((n+m)/2)); p = u.crosspoint(v); r = Line(a,b).dispointtoseg(p); } //输入 void input(){ p.input(); scanf("%lf",&r); } //输出 void output(){ printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r); } bool operator == (circle v){ return (p==v.p) && sgn(r-v.r)==0; } bool operator < (circle v)const{ return ((p 0)return 5; if(sgn(d-r-v.r) == 0)return 4; double l = fabs(r-v.r); if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3; if(sgn(d-l)==0)return 2; if(sgn(d-l)<0)return 1; } //`求两个圆的交点,返回0表示没有交点,返回1是一个交点,2是两个交点` //`需要relationcircle` //`测试:UVA12304` int pointcrosscircle(circle v,Point &p1,Point &p2){ int rel = relationcircle(v); if(rel == 1 || rel == 5)return 0; double d = p.distance(v.p); double l = (d*d+r*r-v.r*v.r)/(2*d); double h = sqrt(r*r-l*l); Point tmp = p + (v.p-p).trunc(l); p1 = tmp + ((v.p-p).rotleft().trunc(h)); p2 = tmp + ((v.p-p).rotright().trunc(h)); if(rel == 2 || rel == 4) return 1; return 2; } //`求直线和圆的交点,返回交点个数` int pointcrossline(Line v,Point &p1,Point &p2){ if(!(*this).relationline(v))return 0; Point a = v.lineprog(p); double d = v.dispointtoline(p); d = sqrt(r*r-d*d); if(sgn(d) == 0){ p1 = a; p2 = a; return 1; } p1 = a + (v.e-v.s).trunc(d); p2 = a - (v.e-v.s).trunc(d); return 2; } //`得到过a,b两点,半径为r1的两个圆` int gercircle(Point a,Point b,double r1,circle &c1,circle &c2){ circle x(a,r1),y(b,r1); int t = x.pointcrosscircle(y,c1.p,c2.p); if(!t)return 0; c1.r = c2.r = r; return t; } //`得到与直线u相切,过点q,半径为r1的圆` //`测试:UVA12304` int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){ double dis = u.dispointtoline(q); if(sgn(dis-r1*2)>0)return 0; if(sgn(dis) == 0){ c1.p = q + ((u.e-u.s).rotleft().trunc(r1)); c2.p = q + ((u.e-u.s).rotright().trunc(r1)); c1.r = c2.r = r1; return 2; } Line u1 = Line((u.s + (u.e-u.s).rotleft().trunc(r1)),(u.e + (u.e-u.s).rotleft().trunc(r1))); Line u2 = Line((u.s + (u.e-u.s).rotright().trunc(r1)),(u.e + (u.e-u.s).rotright().trunc(r1))); circle cc = circle(q,r1); Point p1,p2; if(!cc.pointcrossline(u1,p1,p2))cc.pointcrossline(u2,p1,p2); c1 = circle(p1,r1); if(p1 == p2){ c2 = c1; return 1; } c2 = circle(p2,r1); return 2; } //`同时与直线u,v相切,半径为r1的圆` //`测试:UVA12304` int getcircle(Line u,Line v,double r1,circle &c1,circle &c2,circle &c3,circle &c4){ if(u.parallel(v))return 0;//两直线平行 Line u1 = Line(u.s + (u.e-u.s).rotleft().trunc(r1),u.e + (u.e-u.s).rotleft().trunc(r1)); Line u2 = Line(u.s + (u.e-u.s).rotright().trunc(r1),u.e + (u.e-u.s).rotright().trunc(r1)); Line v1 = Line(v.s + (v.e-v.s).rotleft().trunc(r1),v.e + (v.e-v.s).rotleft().trunc(r1)); Line v2 = Line(v.s + (v.e-v.s).rotright().trunc(r1),v.e + (v.e-v.s).rotright().trunc(r1)); c1.r = c2.r = c3.r = c4.r = r1; c1.p = u1.crosspoint(v1); c2.p = u1.crosspoint(v2); c3.p = u2.crosspoint(v1); c4.p = u2.crosspoint(v2); return 4; } //`同时与不相交圆cx,cy相切,半径为r1的圆` //`测试:UVA12304` int getcircle(circle cx,circle cy,double r1,circle &c1,circle &c2){ circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r); int t = x.pointcrosscircle(y,c1.p,c2.p); if(!t)return 0; c1.r = c2.r = r1; return t; } //`过一点作圆的切线(先判断点和圆的关系)` //`测试:UVA12304` int tangentline(Point q,Line &u,Line &v){ int x = relation(q); if(x == 2)return 0; if(x == 1){ u = Line(q,q + (q-p).rotleft()); v = u; return 1; } double d = p.distance(q); double l = r*r/d; double h = sqrt(r*r-l*l); u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h))); v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h))); return 2; } //`求两圆相交的面积` double areacircle(circle v){ int rel = relationcircle(v); if(rel >= 4)return 0.0; if(rel <= 2)return min(area(),v.area()); double d = p.distance(v.p); double hf = (r+v.r+d)/2.0; double ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d)); double a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d)); a1 = a1*r*r; double a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d)); a2 = a2*v.r*v.r; return a1+a2-ss; } //`求圆和三角形pab的相交面积` //`测试:POJ3675 HDU3982 HDU2892` double areatriangle(Point a,Point b){ if(sgn((p-a)^(p-b)) == 0)return 0.0; Point q[5]; int len = 0; q[len++] = a; Line l(a,b); Point p1,p2; if(pointcrossline(l,q[1],q[2])==2){ if(sgn((a-q[1])*(b-q[1]))<0)q[len++] = q[1]; if(sgn((a-q[2])*(b-q[2]))<0)q[len++] = q[2]; } q[len++] = b; if(len == 4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]); double res = 0; for(int i = 0;i < len-1;i++){ if(relation(q[i])==0||relation(q[i+1])==0){ double arg = p.rad(q[i],q[i+1]); res += r*r*arg/2.0; } else{ res += fabs((q[i]-p)^(q[i+1]-p))/2.0; } } return res; } }; Point a,b; circle c; Line l; int main() { a.input(); b.input(); c.input(); l=Line(a,b); if(c.relationseg(l)!=2) { printf("%.6lf\n",l.length()); } else { double A=acos(c.r/a.distance(c.p)); double B=acos(c.r/b.distance(c.p)); double sum=c.p.rad(a,b); double C=sum-A-B; double ans=0; double la,lb; la=a.distance(c.p); lb=b.distance(c.p); ans+=la*sin(A); ans+=lb*sin(B) ; ans+=c.r*C; printf("%.6lf\n",ans); } } B 组队
排序,枚举队伍最小值然后二分求出该情况下的队伍人数,即可
#include
using namespace std; int T; int n,m; int a[200005]; int main() { scanf("%d",&T) ; while(T--) { scanf("%d%d",&n,&m); for(int i=0;i C 十面埋伏
DFS暴力即可
#include
#define pai pair using namespace std; int n,m; char a[505][505]; int b[505][505]; int main() { scanf("%d%d",&n,&m); memset(a,'.',sizeof(a)); for(int i=1;i<=n;i++) { scanf("%s",a[i]+1); } queue p; p.push(pai(0,0)); while(p.size())//BFS 对外围'.' 染色 { pai P=p.front(); p.pop(); int i=P.first; int j=P.second; int aa[4]={-1,0,1,0}; int bb[4]={0,-1,0,1}; for(int k=0;k<4;k++) { int ii=i+aa[k]; int jj=j+bb[k]; if(ii>=0&&jj>=0&&ii<=n&&jj<=m&&a[ii][jj]=='.'&&b[ii][jj]==0) { b[ii][jj]=1; p.push(pai(ii,jj)); } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]=='#')//暴力改成 '*' { if(a[i-1][j]=='.') a[i-1][j]='*'; if(a[i][j-1]=='.') a[i][j-1]='*'; if(a[i+1][j]=='.') a[i+1][j]='*'; if(a[i][j+1]=='.') a[i][j+1]='*'; } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]=='*') { if(b[i][j])a[i][j]='*'; else a[i][j]='.'; //敌人内部不需要士兵 } } } for(int i=1;i<=n;i++) { printf("%s\n",a[i]+1); } } D 牛妹吃豆子
二维差分例题
#include
#define ll long long using namespace std; int n,m,k,q; ll a[2003][2003]; int main() { scanf("%d%d%d%d",&n,&m,&k,&q); for(int i=0;i E 旅旅旅游
3次最短路
1.数组D[i] 求1起点到 i 的最短路2.数组d[i] 求n 起点到 i 的最短路
枚举每条边 u v c
若满足 d[u]+D[v]+c==D[n]||d[v]+D[u]+c==D[n] 则在最短路径上,忽略
若不满足 加入GG边集,重新建图
3. 再次 ,数组D[i] 求1起点到 i 的最短路
枚举每个城市,若D[i] ==inf 说明不存在路径可达 非法 输出NO
#include
#define pai pair #define ll long long using namespace std; int n,m; vector G[100005],g[100005]; struct node { int u,v,c; }N[500005]; ll D[100005],d[100005]; void dij1() { priority_queue ,greater > q; D[1]=0; q.push(pai(0,1)); while(q.size()) { pai P=q.top(); q.pop(); int F=P.first,S=P.second; if(F>D[S]) continue; for(auto T:G[S]) { if(T.first+D[S] ,greater > q; d[n]=0; q.push(pai(0,n)); while(q.size()) { pai P=q.top(); q.pop(); int F=P.first,S=P.second; if(F>d[S]) continue; for(auto T:G[S]) { if(T.first+d[S] ,greater > q; D[1]=0; q.push(pai(0,1)); while(q.size()) { pai P=q.top(); q.pop(); int F=P.first,S=P.second; if(F>D[S]) continue; for(auto T:g[S]) { if(T.first+D[S] F 斗兽棋
每个动物编号
if(牛妹赢 ) puts("tiangou txdy");
else puts("tiangou yiwusuoyou");
#include
using namespace std; char s[20],ss[20]; int main() { map mp; mp['e']=0; mp['t']=1; mp['c']=2; mp['m']=3; scanf("%s %s",s,ss); int a=mp[s[0]]; int b=mp[ss[0]]; if((b+1)%4==a) puts("tiangou txdy"); else puts("tiangou yiwusuoyou"); } G 做题
排序,贪心 注意long long
#include
#define ll long long using namespace std; ll n; long long m; ll a[500005]; int main() { scanf("%lld%lld",&n,&m); for(int i=0;i H 人人都是好朋友
每个下手用map 取1~num 编号 ,离散化
并查集 即可
#include
using namespace std; int f[2000006],dep[1000006]; struct node { int a,b,c; }N[1000006]; int find(int x) { if(f[x]==x) return x; else f[x]=find(f[x]); } void uin(int x,int y) { int fx=find(x); int fy=find(y); if(fx==fy) return ; if(dep[fx] fa; int num=1; for(int i=0;i I 求和
求每个节点dfs序 保存每个节点子树的dfs序范围 L[i],R[i]
建立线段树,即可
自省:
up(1,1,n,L[a],x) !!!
NO up(1,1,4000006,L[a],x)
#include
#define ll long long #define ls o*2 #define rs o*2+1 #define mid (l+r)/2 using namespace std; int n,m,k; ll tree[8000006]; vector G[1000006]; ll v[1000006]; int L[1000006]; int R[1000006]; int cnt=0; void dfs(int a,int fa) { L[a]=++cnt; for(auto P:G[a]) { if(P==fa) continue; dfs(P,a); } R[a]=cnt; } void up(int o,int l,int r,int p,ll v) { if(l==r) { tree[o]+=v; return ; } if(p<=mid) up(ls,l,mid,p,v); else up(rs,mid+1,r,p,v); tree[o]=tree[ls]+tree[rs]; } ll qu(int o,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) { return tree[o]; } ll sum=0; if(ql<=mid) sum+=qu(ls,l,mid,ql,qr); if(mid+1<=qr) sum+=qu(rs,mid+1,r,ql,qr); return sum; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) { scanf("%lld",&v[i]); } for(int i=0;i J 建设道路
每个城市ai的度为n-1 则会计算n-1次
可利用前缀和求
两部分相加即可
关于取模 :务必饱和时取模!吝啬你就wa了(一顿乱%)
#include
#define ll long long #define mod 1000000007 using namespace std; int n; ll a[500005]; int main() { scanf("%d",&n); ll ans=0; for(int i=0;i