Basic
通用模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
template<typename T>
inline T read(){
T x=0,f=0;char ch=getchar();
while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
#define rdi read<int>
#define rdll read<ll>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int main(){
#ifdef LOCAL
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
return 0;
}
读入优化
namespace GTR {
const int bufl = 1 << 15;
char buf[bufl], *s = buf, *t = buf;
inline int fetch() {
if (s == t) { t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t) return EOF; }
return *s++;
}
inline int read() {
int a = 0, b = 1, c = fetch();
while (c < 48 || c > 57) b ^= c == '-', c = fetch();
while (c >= 48 && c <= 57) a = (a << 1) + (a << 3) + c - 48, c = fetch();
return b ? a : -a;
}
} using GTR::read;
DS
Segment Tree Beats
区间取 min,区间加,区间求和。
struct Node{
ll mx,smx,sum;
int cnt;
friend Node operator + (Node a,Node b){
if(!a.cnt) return b;
if(!b.cnt) return a;
if(a.mx<b.mx) swap(a,b);
if(a.mx>b.mx) return {a.mx,max(a.smx,b.mx),a.sum+b.sum,a.cnt};
else return {a.mx,max(a.smx,b.smx),a.sum+b.sum,a.cnt+b.cnt};
}
}t[N*4];
ll tmx[N*4],tsum[N*4];
void pushup(int now) {t[now]=t[lson]+t[rson];}
void upd1(int now,ll t1){
if(t[now].mx<t1) return;
t[now].sum-=(t[now].mx-t1)*t[now].cnt,t[now].mx=tmx[now]=t1;
}
void upd2(int now,ll t2){
t[now].mx+=t2,t[now].smx+=t2,t[now].sum+=t[now].cnt1*t2,tsum[now]+=t2,tmx[now]+=t2;
}
void pushdown(int now){
if(tsum[now]) upd2(lson,tsum[now]),upd2(rson,tsum[now]),tsum[now]=0;
if(tmx[now]!=INF) upd1(lson,tmx[now]),upd1(rson,tmx[now]),tmx[now]=INF;
}
void add(int now,int l,int r,int x,int y,ll val){
//与普通线段树相同
//调用 upd2
}
void chkmin(int now,int l,int r,int x,int y,ll val){
if(x>y||val>=t[now].mx) return;
if(x<=l&&r<=y&&val>t[now].smx) return upd1(now,val);
if(l==r) {t[now].mx=min(t[now].mx,val),t[now].sum=t[now].mx;return;}
pushdown(now);
if(x<=mid) chkmin(lson,l,mid,x,y,val);
if(y>mid) chkmin(rson,mid+1,r,x,y,val);
pushup(now);
}
void query(){
//与普通线段树相同
}
李超树
支持插入直线,查询,合并。
struct Line{
ll k,b;
ll operator ()(ll x) const{return k*x+b;}
};
struct SGT{
#define lson (t[now].ls)
#define rson (t[now].rs)
#define mid ((l+r)>>1)
struct Node{Line cur;int ls,rs;}t[N*60];
int tot;
int newnode(){
t[++tot]={{0,INFl},0,0};
return tot;
}
void insert(int &now,int l,int r,Line x){
if(!now) now=newnode();
if(t[now].cur(mid)>x(mid)) swap(t[now].cur,x);
if(l==r) return;
if(x(l)<t[now].cur(l)) insert(lson,l,mid,x);
if(x(r)<t[now].cur(r)) insert(rson,mid+1,r,x);
}
ll query(int now,int l,int r,int x){
if(!now) return INFl;
ll ret=t[now].cur(x);
if(l==r) return ret;
ret=min(ret,(x<=mid?query(lson,l,mid,x):query(rson,mid+1,r,x)));
return ret;
}
void merge(int &now1,int now2,int l,int r){
if(!now1||!now2) {now1|=now2;return;}
if(l<r){
merge(t[now1].ls,t[now2].ls,l,mid);
merge(t[now1].rs,t[now2].rs,mid+1,r);
}
insert(now1,l,r,t[now2].cur);
}
#undef lson
#undef rson
#undef mid
}t;
历史最值线段树
支持区间加减,单点修改(区间赋值以后补)。
struct SGT{
#define lson (now<<1)
#define rson (now<<1|1)
#define mid ((l+r)>>1)
struct Node{ll mx,hmx,ad,h_ad;}t[N*4];
void upd(int now,ll ad,ll h_ad){
t[now].hmx=max(t[now].mx+h_ad,t[now].hmx),t[now].mx+=ad;
t[now].h_ad=max(t[now].h_ad,t[now].ad+h_ad),t[now].ad+=ad;
}
void pushdown(int now){
if(t[now].ad||t[now].h_ad){
upd(lson,t[now].ad,t[now].h_ad),upd(rson,t[now].ad,t[now].h_ad);
t[now].ad=t[now].h_ad=0;
}
}
void pushup(int now){
t[now].mx=max(t[lson].mx,t[rson].mx);
t[now].hmx=max({t[now].mx,t[lson].hmx,t[rson].hmx});
}
void build(int now,int l,int r){
t[now].mx=t[now].hmx=-INFl;
if(l==r) return;
build(lson,l,mid);build(rson,mid+1,r);
}
void add(int now,int l,int r,int x,int y,ll val){
if(x<=l&&r<=y) {upd(now,val,max(val,0ll));return;}
pushdown(now);
if(x<=mid) add(lson,l,mid,x,y,val);
if(y>mid) add(rson,mid+1,r,x,y,val);
pushup(now);
}
void set(int now,int l,int r,int x,ll val){
if(l==r){
t[now].mx=val;
t[now].hmx=max(t[now].hmx,t[now].mx);
return;
}
pushdown(now);
x<=mid?set(lson,l,mid,x,val):set(rson,mid+1,r,x,val);
pushup(now);
}
ll query(int now,int l,int r,int x,int y){
if(x<=l&&r<=y) return t[now].hmx;
ll ret=-INFl;pushdown(now);
if(x<=mid) ret=max(ret,query(lson,l,mid,x,y));
if(y>mid) ret=max(ret,query(rson,mid+1,r,x,y));
return ret;
}
#undef lson
#undef rson
#undef mid
};
Geometry
向量类
struct Vec{
double x,y;
friend bool operator == (Vec a,Vec b){return a.x==b.x&&a.y==b.y;}
double abs() const{return hypot(x,y);}
double deg() const{return atan2(y,x);}
};
Vec operator + (const Vec &a,const Vec &b) {return {a.x+b.x,a.y+b.y};}
Vec operator - (const Vec &a,const Vec &b) {return {a.x-b.x,a.y-b.y};}
double dot(const Vec &a,const Vec &b) {return a.x*b.x+a.y*b.y;}
double cross(const Vec &a,const Vec &b) {return a.x*b.y-a.y*b.x;}
凸包
vector<Vec> convex(vector<Vec> v){
int cnt=v.size();
for(int i=1;i<cnt;i++)
if(v[i].y<v[0].y||(v[i].y==v[0].y&&v[i].x<v[0].x)) swap(v[i],v[0]);
sort(v.begin()+1,v.end(),[&](Vec a,Vec b){
double val=cross(a-v[0],b-v[0]);
return fabs(val)<eps?mp(a.x,a.y)<mp(b.x,b.y):val>0;
});
static int st[N],tp;
st[tp=1]=0;
for(int i=1;i<cnt;i++){
while(tp>1&&cross(v[i]-v[st[tp-1]],v[st[tp]]-v[st[tp-1]])>=0) --tp;
st[++tp]=i;
}
vector<Vec> ret(tp);
for(int i=0;i<tp;i++) ret[i]=v[st[i+1]];
return ret;
}
多边形面积
double area(const vector<Vec> &a){
int siz=a.size();
double sum=0;
for(int i=0;i<siz;i++){
int nxt=(i+1>=siz?i+1-siz:i+1);
sum+=cross(a[i],a[nxt]);
}
return abs(sum/2);
}