NOIP常见模板集合

时间:2023-03-10 00:39:34
NOIP常见模板集合

Preface

这篇博客记录的是我联赛前虽然只有两天了的打板子记录。

只求真的能给我起到些作用吧,一般按照难度排序。

而且从这篇博客开始我会用H3的标题代替H4

为了节约篇幅,以下的代码一般均以class的形式给出,模板题均来自Luogu


快读快输(文件操作)

这是基础中的基础吧,这个感觉敲出来还是没什么问题的(默认不读/输负数)

class FileInputOutput
{
private:
#define S 1<<21
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int pt[15],Ftop;
public:
FileInputOutput() { A=B=Fin; Ftop=0; }
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
inline void write(int x,char ch)
{
if (!x) return (void)(pc('0'),pc(ch)); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc(ch);
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef S
#undef tc
#undef pc
}F;

P1177 【模板】快速排序

快排模板?调用sort也太没技术含量了吧?

写一发松式基排,感觉速率还可以吧,一次过这个一次过不了退役算了

class Radix_Sort
{
private:
int cnt1[Radix+1],cnt2[Radix+1],cnt3[Radix+1],cnt4[Radix+1]; u32 b[N];
public:
inline void sort(u32 *a,int n)
{
RI i; for (i=1;i<=n;++i)
{
++cnt1[a[i]&Radix]; ++cnt2[a[i]>>8&Radix];
++cnt3[a[i]>>16&Radix]; ++cnt4[a[i]>>24&Radix];
}
for (i=1;i<=Radix;++i)
{
cnt1[i]+=cnt1[i-1]; cnt2[i]+=cnt2[i-1];
cnt3[i]+=cnt3[i-1]; cnt4[i]+=cnt4[i-1];
}
for (i=n;i;--i) b[cnt1[a[i]&Radix]--]=a[i];
for (i=n;i;--i) a[cnt2[b[i]>>8&Radix]--]=b[i];
for (i=n;i;--i) b[cnt3[a[i]>>16&Radix]--]=a[i];
h+++++++ for (i=n;i;--i) a[cnt4[b[i]>>24&Radix]--]=b[i];
}
}R;

l


P3367 【模板】并查集

写了个按秩合并,然后getfather忘记returnMLE了一大片

class FindUnionSet
{
private:
int father[N],size[N];
inline void swap(int &x,int &y)
{
int t=x; x=y; y=t;
}
inline int getfather(int x)
{
return father[x]^x?father[x]=getfather(father[x]):x;
}
public:
inline void init(void)
{
for (RI i=1;i<=n;++i) father[i]=i,size[i]=1;
}
inline bool Identify(int x,int y)
{
return getfather(x)==getfather(y);
}
inline void Union(int x,int y)
{
x=getfather(x); y=getfather(y);
if (x==y) return; if (size[x]<size[y]) swap(x,y);
father[y]=x; size[x]+=size[x]==size[y]; size[y]=0;
}
}S;

P1226 【模板】快速幂||取余运算

快速幂板子题居然WA了两发,注意要特判模数为\(0\)的情况。

inline int quick_pow(int x,int p,int mod,int mul=1)
{
if (mod==1) return 0;
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}

P3383 【模板】线性筛素数

不想写MR,还是写个欧拉筛即可。

#define Pi prime[j]
inline void Euler(int n)
{
vis[1]=1; for (RI i=2;i<=n;++i)
{
if (!vis[i]) prime[++cnt]=i;
for (RI j=1;j<=cnt&&i*Pi<=n;++j)
{
vis[i*Pi]=1; if (i%Pi==0) break;
}
}
}
#undef Pi

P3378 【模板】堆

懒得写堆了因为我不会,又不想左偏树,直接STL好了。


P3370 【模板】字符串哈希

写了发挂链Hash,不过速度有点慢,说实话不如用map

class Hasher_Solver
{
private:
#define P 2333333
struct Hasher
{
int nxt; string val;
}link[10005]; int head[P],cnt;
inline int Hash(string s)
{
int len=s.size(),ret=0; for (RI i=0;i<len;++i)
ret=((ret<<3)+(ret<<1)+s[i])%P; return ret;
}
public:
inline bool find(string s)
{
int now=Hash(s); bool is_exist=0;
for (RI i=head[now];i;i=link[i].nxt)
if (link[i].val==s) { is_exist=1; break; }
return is_exist;
}
inline void insert(string s)
{
int now=Hash(s); link[++cnt]=(Hasher){head[now],s}; head[now]=cnt;
}
}H;

P3366 【模板】最小生成树

一般推荐写Kruskal,并查集参照上面。

class MST_Kruskal
{
private:
int cur; long long ans;
public:
inline void Kruskal(void)
{
RI i; for (sort(a+1,a+m+1),S.init(),i=1;i<=m;++i)
if (!S.Identify(a[i].l,a[i].r)) S.Union(a[i].l,a[i].r),ans+=a[i].val,++cur;
if (cur!=n-1) puts("orz"); else printf("%lld",ans);
}
}K;

Prim也写一发吧,虽然并没有什么卵用

class MST_Prim
{
private:
struct data
{
int id,val;
data(int Id=0,int Val=0) { id=Id; val=Val; }
inline friend bool operator <(data a,data b)
{
return a.val>b.val;
}
}; priority_queue <data> small; long long ans; int cur,dis[N]; bool vis[N];
public:
#define to e[i].to
inline void Prim(void)
{
memset(dis,63,sizeof(dis)); small.push(data(1,dis[1]=0));
while (!small.empty())
{
int now=small.top().id; small.pop(); if (vis[now]) continue;
++cur; ans+=dis[now]; vis[now]=1; for (RI i=head[now];i;i=e[i].nxt)
if (dis[to]>e[i].v) small.push(data(to,dis[to]=e[i].v));
}
if (cur!=n) puts("orz"); else printf("%lld",ans);
}
#undef to
}P;

P3371 【模板】单源最短路径(弱化版)

这个练习一下SPFA好了虽然它已经死了,标准版再写DJ

class SLF_SPFA
{
private:
deque <int> q; int dis[N]; bool vis[N];
public:
#define to e[i].to
inline void SPFA(int s)
{
RI i; for (RI i=1;i<=n;++i) dis[i]=INF; vis[s]=1; dis[s]=0; q.push_front(s);
while (!q.empty())
{
int now=q.front(); q.pop_front(); vis[now]=0;
for (i=head[now];i;i=e[i].nxt) if (dis[to]>dis[now]+e[i].v)
{
dis[to]=dis[now]+e[i].v; if (!vis[to])
{
if (q.empty()||dis[q.front()]>dis[to])
q.push_front(to); else q.push_back(to); vis[to]=1;
}
}
}
}
#undef to
inline void print(void)
{
for (RI i=1;i<=n;++i) F.write(dis[i]);
}
}S;

P3374 【模板】树状数组 1

手速码树状数组,不要像某九条可怜一样就好。

class BIT
{
private:
long long bit[N];
#define lowbit(x) x&-x
public:
inline void add(RI x,int y)
{
for (;x<=n;x+=lowbit(x)) bit[x]+=y;
}
inline long long get(RI x,long long ret=0)
{
for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
}
#undef lowbit
}T;

P3368 【模板】树状数组 2

类似于模板1,再之前的基础上查分一下就好了。核心部分:

F.read(opt),F.read(x),(opt^2?F.read(y),F.read(z),T.add(x,z),T.add(y+1,-z):F.write(T.get(x)));

P3382 【模板】三分法

按题意搞就好了,函数的计算可以套一个秦九昭算法

inline DB F(DB x)
{
DB ret=0; for (RI i=n;~i;--i)
ret=ret*x+a[n-i]; return ret;
}
DB lmid,rmid; while (r-l>EPS)
{
lmid=l+(r-l)/3.0; rmid=r-(r-l)/3.0;
if (F(lmid)-F(rmid)<-EPS) l=lmid; else r=rmid;
}

P3865 【模板】ST表

简单的RMQ不做多解释

class RMQ_Solver
{
private:
#define P 18
int log[N],f[N][P];
inline int max(int a,int b)
{
return a>b?a:b;
}
inline void swap(int &a,int &b)
{
int t=a; a=b; b=t;
}
public:
inline void log_init(void)
{
for (RI i=2;i<=n;++i) log[i]=log[i>>1]+1;
}
inline void RMQ_init(void)
{
RI i; for (i=1;i<=n;++i) f[i][0]=a[i];
for (RI j=1;j<P;++j) for (i=1;i+(1<<j)-1<=n;++i)
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
inline int query(int l,int r)
{
if (l>r) swap(l,r); int t=log[r-l+1];
return max(f[l][t],f[r-(1<<t)+1][t]);
}
#undef P
}R;

P3390 【模板】矩阵快速幂

矩阵板子,习惯封装成结构体。

struct Matrix
{
int n,a[N][N];
Matrix(int N=0) { n=N; memset(a,0,sizeof(a)); }
inline void input(void)
{
for (RI i=1;i<=n;++i) for (RI j=1;j<=n;++j) F.read(a[i][j]);
}
inline void output(void)
{
for (RI i=1;i<=n;++i) for (RI j=1;j<=n;++j) F.write(a[i][j],j^n?' ':'\n');
}
inline void Cri_init(void)
{
for (RI i=1;i<=n;++i) a[i][i]=1;
}
}; int n; long long k;
inline Matrix operator *(Matrix A,Matrix B)
{
Matrix C(n); for (RI i=1;i<=n;++i)
for (RI j=1;j<=n;++j) for (RI k=1;k<=n;++k)
inc(C.a[i][j],1LL*A.a[i][k]*B.a[k][j]%mod);
return C;
}
inline Matrix operator ^(Matrix A,long long p)
{
Matrix T(n); T.Cri_init(); for (;p;p>>=1,A=A*A)
if (p&1) T=T*A; return T;
}

P3375 【模板】KMP字符串匹配

KMP我除了板子什么都不会。。。

class KMQ_Solver
{
private:
int nxt[N],ans;
public:
inline void Get_nxt(void)
{
int len=0; for (RI i=2;i<=m;++i)
{
while (len&&s2[len+1]!=s2[i]) len=nxt[len];
if (s2[len+1]==s2[i]) ++len; nxt[i]=len;
}
}
inline void KMP(void)
{
int len=0; for (RI i=1;i<=n;++i)
{
while (len&&s2[len+1]!=s1[i]) len=nxt[len];
if (s2[len+1]==s1[i]) ++len;
if (len==m) printf("%d\n",i-len+1),len=nxt[len];
}
}
inline void print(void)
{
for (RI i=1;i<=m;++i) printf("%d ",nxt[i]);
}
}K;

P3811 【模板】乘法逆元

据说这题逆元板子卡快速幂exgcd,只能写线性求逆元

inline void Get_inv(int n)
{
RI i; inv[1]=1; for (i=2;i<=n;++i)
inv[i]=(-1LL*inv[p%i]*(p/i)%p+p)%p;
}

P3372 【模板】线段树 1

大力敲板子就好了,不要忘记清空标记。

class FileInputOutput
{
private:
#define S 1<<21
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int pt[25],Ftop;
public:
FileInputOutput() { A=B=Fin; Ftop=0; }
inline void read(int &x)
{
x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); x*=flag;
}
inline void write(LL x)
{
if (!x) return (void)(pc('0'),pc('\n')); if (x<0) x=-x,pc('-'); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef S
#undef tc
#undef pc
}F;
class Segment_Tree
{
private:
struct Segment
{
LL sum,tag;
}node[N<<2];
#define pushup(x) node[x].sum=node[x<<1].sum+node[x<<1|1].sum
inline void pushdown(int now,int ltot,int rtot)
{
if (!node[now].tag) return; int val=node[now].tag;
node[now<<1].tag+=val; node[now<<1].sum+=1LL*ltot*val;
node[now<<1|1].tag+=val; node[now<<1|1].sum+=1LL*rtot*val;
node[now].tag=0;
}
public:
inline void build(int now,int l,int r)
{
if (l==r) return (void)(node[now].sum=a[l]); int mid=l+r>>1;
build(now<<1,l,mid); build(now<<1|1,mid+1,r); pushup(now);
}
#define O beg,end
inline void modify(int now,int l,int r,int beg,int end,int val)
{
if (l>=beg&&r<=end) return (void)(node[now].tag+=val,node[now].sum+=1LL*(r-l+1)*val);
int mid=l+r>>1; pushdown(now,mid-l+1,r-mid); if (beg<=mid) modify(now<<1,l,mid,O,val);
if (end>mid) modify(now<<1|1,mid+1,r,O,val); pushup(now);
}
inline LL query(int now,int l,int r,int beg,int end)
{
if (l>=beg&&r<=end) return node[now].sum; int mid=l+r>>1; pushdown(now,mid-l+1,r-mid);
LL ret=0; if (beg<=mid) ret+=query(now<<1,l,mid,O); if (end>mid) ret+=query(now<<1|1,mid+1,r,O); return ret;
}
#undef O
#undef pushup
}T;

P1939 【模板】矩阵加速(数列)

手玩一下递推式就好了,矩阵快速幂参考上面。构造代码:

inline void Cri_init(void)
{
for (RI i=1;i<=n;++i) a[i][i]=1;
}
inline void Base_init(void)
{
a[1][1]=a[2][1]=a[3][1]=1;
}
inline void DT_init(void)
{
a[1][2]=a[2][3]=a[3][1]=a[3][3]=1;
}

P3379 【模板】最近公共祖先(LCA)

写发最常用的倍增把,RMQ没什么用,Tarjan太烦还要离线。树剖的话。。。板子题再写吧。

class LCA_DoubleIncreased
{
private:
#define P 20
int dep[N],father[N][P];
inline void swap(int &a,int &b)
{
int t=a; a=b; b=t;
}
inline void reset(int now)
{
for (RI i=0;i<P-1;++i) if (father[now][i])
father[now][i+1]=father[father[now][i]][i]; else break;
}
public:
#define to e[i].to
inline void DFS(int now,int fa)
{
dep[now]=dep[fa]+1; reset(now);
for (RI i=head[now];i;i=e[i].nxt)
if (to!=fa) father[to][0]=now,DFS(to,now);
}
#undef to
inline int LCA(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y); RI i;
for (i=P-1;~i;--i) if (dep[father[x][i]]>=dep[y])
x=father[x][i]; if (x==y) return x;
for (i=P-1;~i;--i) if (father[x][i]!=father[y][i])
x=father[x][i],y=father[y][i]; return father[x][0];
}
}T;

P4779 【模板】单源最短路径(标准版)

写了DJ,不想写堆然后就写了线段树优化当然没有写zkw线段树

class Segment_Tree
{
private:
struct Segment
{
int mi,id;
Segment(int Mi=INF,int Id=0) { mi=Mi; id=Id; }
}node[N<<2];
#define pushup(now) node[now]=node[now<<1].mi<node[now<<1|1].mi?node[now<<1]:node[now<<1|1];
public:
inline void modify(int now,int l,int r,int id,int val)
{
if (l==r) return (void)(node[now].mi=val,node[now].id=l);
int mid=l+r>>1; if (id<=mid) modify(now<<1,l,mid,id,val);
else modify(now<<1|1,mid+1,r,id,val); pushup(now);
}
inline int query(void)
{
return node[1].id;
}
inline bool empty(void)
{
return node[1].mi==INF;
}
#undef pushup
}T;
class Dijkstra_Solver
{
private:
int dis[N];
public:
#define to e[i].to
inline void Dijkstra(int s)
{
RI i; for (i=1;i<=n;++i) dis[i]=INF; T.modify(1,1,n,s,dis[s]=0);
while (!T.empty())
{
int now=T.query(); T.modify(1,1,n,now,INF);
for (RI i=head[now];i;i=e[i].nxt) if (dis[to]>dis[now]+e[i].v)
T.modify(1,1,n,to,dis[to]=dis[now]+e[i].v);
}
}
#undef to
inline void print(void)
{
for (RI i=1;i<=n;++i) F.write(dis[i]);
}
}D;

P3807 【模板】卢卡斯定理

这个板子太弱了吧,虽然直接暴力也能过。卢卡斯定理\(C_n^m\operatorname{mod}p=C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor}\cdot C_{n\operatorname{mod}p}^{m\operatorname{mod}p}\)

inline void init(void)
{
RI i; for (fact[0]=i=1;i<p;++i) fact[i]=1LL*fact[i-1]*i%p;
for (inv[p-1]=quick_pow(fact[p-1],p-2),i=p-2;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%p;
}
inline int C(int n,int m)
{
if (n<m) return 0; if (!n) return 1;
return 1LL*fact[n]*inv[m]%p*inv[n-m]%p;
}
inline int Lucas(int n,int m)
{
if (n<m) return 0; if (!n) return 1;
return 1LL*Lucas(n/p,m/p)*C(n%p,m%p)%p;
}

P1439 【模板】最长公共子序列

因为这个是排列,所以我们可以离散化一下\(A\)中每个数在\(B\)中出现的位置,然后就是一个LIS了,直接二分维护单调性即可。

class LIS
{
private:
int r[N],stack[N],top;
inline int find(int x)
{
int l=1,r=top-1,res=-1,mid; while (l<=r)
if (stack[mid=l+r>>1]<x) res=mid,l=mid+1; else r=mid-1;
return res;
}
public:
inline void init(void)
{
RI i; for (i=1;i<=n;++i) r[a[i]]=i;
for (i=1;i<=n;++i) b[i]=r[b[i]];
}
inline void solve(void)
{
stack[top=1]=b[1]; for (RI i=2;i<=n;++i)
{
if (b[i]<stack[1]) stack[1]=b[i];
if (b[i]>stack[top]) stack[++top]=b[i];
else stack[find(b[i])+1]=b[i];
}
printf("%d",top);
}
}L;

P2197 【模板】nim游戏

这个结论吧,具体证明好像我也不会呵。

RI i; for (ret=0,F.read(n),i=1;i<=n;++i)
F.read(x),ret^=x; puts(ret?"Yes":"No");

P3386 【模板】二分图匹配

挺简短的匈牙利算法Dinic网络流的时候再写。

class Brinary_Graph_Matching
{
private:
int from[N],t[N];
public:
#define to e[i].to
inline bool find(int now,int idx)
{
for (RI i=head[now];i;i=e[i].nxt)
{
if (t[to]==idx) continue; t[to]=idx;
if (!from[to]||find(from[to],idx)) return from[to]=now,1;
} return 0;
}
#undef to
}M;

P2613 【模板】有理数取余

这TM就一SB题,一遍读入一边取模就好了,别忘了判无解!读入部分:

inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=((x<<3)+(x<<1)+(ch&15))%mod,isdigit(ch=tc()));
}

P3805 【模板】manacher算法

我为数不多会的字符串算法其实不会,板子挺好写的。

class Manacher_Solver
{
private:
char ns[N<<1]; int r[N<<1],n,pos,mx,ans;
inline int min(int a,int b)
{
return a<b?a:b;
}
inline int max(int a,int b)
{
return a>b?a:b;
}
public:
inline void change(void)
{
ns[0]='$'; ns[n=1]='%'; for (RI i=1;i<=len;++i) ns[++n]=s[i],ns[++n]='%';
}
inline void Manacher(void)
{
for (RI i=1;i<=n;++i)
{
if (i<mx) r[i]=min(r[(pos<<1)-i],mx-i); else r[i]=1;
while (ns[i-r[i]]==ns[i+r[i]]) ++r[i];
if (i+r[i]>mx) mx=i+r[i],pos=i; ans=max(ans,r[i]);
}
printf("%d",ans-1);
}
}M;

P3389 【模板】高斯消元法

刚开始把高斯消元写成了行列式消元。。。然后又忘写负号了然后卡了很久才过样例。

inline void swapline(int x)
{
RI now=x+1; while (fabs(a[now][x])<EPS&&now<=n) ++now;
if (now>n) { puts("No Solution"); exit(0); }
swap(a[x],a[now]); swap(val[x],val[now]);
}
inline void check(void)
{
for (RI i=1;i<=n;++i)
{
bool flag=0; for (RI j=1;j<=n;++j) flag|=fabs(a[i][j])>=EPS;
if (!flag) { puts("No Solution"); exit(0); }
}
}
inline void Gauss(void)
{
RI i,j; for (i=1;i<n;++i)
{
if (fabs(a[i][i])<EPS) swapline(i);
for (RI j=i+1;j<=n;++j)
{
if (fabs(a[j][i])<EPS) continue;
double d=-a[j][i]/a[i][i]; a[j][i]=0;
for (RI k=i+1;k<=n;++k) a[j][k]+=d*a[i][k];
val[j]+=d*val[i];
}
}
for (check(),val[n]/=a[n][n],i=n-1;i;--i)
{
double ret=0; for (j=i+1;j<=n;++j) ret+=a[i][j]*val[j];
val[i]=(val[i]-ret)/a[i][i];
}
}

P3388 【模板】割点(割顶)

交的时候Luogu上有个SB在卡评测据说交了2000多发

class Cutting_Point_Solver
{
private:
int dfn[N],low[N],idx,tot; bool cut[N];
inline void miner(int &x,int y)
{
if (y<x) x=y;
}
#define to e[i].to
inline void Tarjan(int now,int fa)
{
dfn[now]=low[now]=++idx; int son=0;
for (RI i=head[now];i;i=e[i].nxt)
if (!dfn[to])
{
Tarjan(to,now); miner(low[now],low[to]); ++son;
if (fa&&low[to]>=dfn[now]) !cut[now]&&(cut[now]=1,++tot);
} else if (to!=fa) miner(low[now],dfn[to]);
if (!fa&&son>=2) !cut[now]&&(cut[now]=1,++tot);
}
#undef to
public:
inline void solve(void)
{
RI i; for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i,0);
for (F.write(tot,'\n'),i=1;i<=n;++i) if (cut[i]) F.write(i,' ');
}
}T;

P3385 【模板】负环

好好写个板子都要卡我,据说判负环不能用SLF优化?去了就A了。

#include<cstdio>
#include<cstring>
#include<queue>
#define RI register int
#define add(x,y,z) e[++cnt]=(edge){y,head[x],z},head[x]=cnt
#define Ms(f,x) memset(f,x,sizeof(f))
using namespace std;
const int N=2005,M=3005;
struct edge
{
int to,nxt,v;
}e[M<<1]; queue <int> q; int t,m,head[N],n,cnt,x,y,z; bool vis[N];
class Minus_Circle_Solver
{
private:
int dis[N],tim[N]; bool vis[N];
public:
#define to e[i].to
inline bool SPFA(void)
{
while (!q.empty()) q.pop(); Ms(dis,63); Ms(vis,0); Ms(tim,0);
dis[1]=0; q.push(1); vis[1]=1;
while (!q.empty())
{
int now=q.front(); q.pop(); vis[now]=0;
if (++tim[now]>=n) return 1; for (RI i=head[now];i;i=e[i].nxt)
if (dis[to]>dis[now]+e[i].v)
{
dis[to]=dis[now]+e[i].v; if (!vis[to])
q.push(to),vis[to]=1;
}
}
return 0;
}
#undef to
}C;
int main()
{
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d%d",&x,&y,&z),add(x,y,z),z>=0?add(y,x,z):0;
puts(C.SPFA()?"YE5":"N0"); for (cnt=0,i=1;i<=n;++i) head[i]=0;
}
return 0;
}

P1919 【模板】A*B Problem升级版(FFT快速傅里叶)

Python题,死也不写高精。NOIP应该不考吧

input()
a=int(input())
b=int(input())
print(a*b)

P3387 【模板】缩点

Tarjan缩一下点之后在DAG上用拓扑排序DP即可,练习到了挺多板子。1A真开心

class Graph_Solver
{
private:
edge ne[M]; int nhead[N],dfn[N],deg[N],low[N],idx,tot,col[N],stack[N],top,q[N],s[N],f[N]; bool vis[N];
inline void miner(int &x,int y)
{
if (y<x) x=y;
}
inline void maxer(int &x,int y)
{
if (y>x) x=y;
}
#define nadd(x,y) ne[++cnt]=(edge){y,nhead[x]},nhead[x]=cnt,++deg[y]
#define to ne[i].to
inline void Top_sort(void)
{
RI i,H=0,T=0; for (i=1;i<=tot;++i) if (!deg[i]) q[++T]=i,f[i]=s[i];
while (H<T)
{
int now=q[++H]; for (i=nhead[now];i;i=ne[i].nxt)
{
maxer(f[to],f[now]+s[to]); maxer(ans,f[to]);
if (!(--deg[to])) q[++T]=to;
}
}
}
#undef to
#define to e[i].to
inline void Tarjan(int now)
{
dfn[now]=low[now]=++idx; stack[++top]=now;
vis[now]=1; for (RI i=head[now];i;i=e[i].nxt)
if (!dfn[to]) Tarjan(to),miner(low[now],low[to]);
else if (vis[to]) miner(low[now],dfn[to]);
if (low[now]==dfn[now])
{
col[now]=++tot; s[tot]=a[now]; vis[now]=0;
while (stack[top]!=now)
{
col[stack[top]]=tot; s[tot]+=a[stack[top]];
vis[stack[top--]]=0;
} --top; maxer(ans,s[tot]);
}
}
public:
inline void solve(void)
{
RI i,j; for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i);
for (cnt=0,j=1;j<=n;++j) for (i=head[j];i;i=e[i].nxt)
if (col[j]!=col[to]) nadd(col[j],col[to]); Top_sort();
}
#undef to
#undef nadd
}G;

P3373 【模板】线段树 2

维护一个乘法一个加法即可,注意先传乘法。刚开始pushup没取模跪了一发。

class Segment_Tree
{
private:
struct Segment
{
int sum,tag_mul,tag_add;
Segment(int Sum=0,int Tag_mul=1,int Tag_add=0)
{
sum=Sum; tag_mul=Tag_mul; tag_add=Tag_add;
}
}node[N<<2];
inline void inc(int &x,int y)
{
if ((x+=y)>=mod) x-=mod;
}
#define pushup(x) node[x].sum=node[x<<1].sum,inc(node[x].sum,node[x<<1|1].sum)
inline void pushdown(int now,int ltot,int rtot)
{
if (node[now].tag_mul!=1||node[now].tag_add)
{
int lc=now<<1,rc=now<<1|1,mt=node[now].tag_mul,at=node[now].tag_add;
node[lc].tag_mul=1LL*node[lc].tag_mul*mt%mod;
node[lc].tag_add=1LL*node[lc].tag_add*mt%mod;
node[lc].sum=1LL*node[lc].sum*mt%mod;
inc(node[lc].tag_add,at); inc(node[lc].sum,1LL*ltot*at%mod);
node[rc].tag_mul=1LL*node[rc].tag_mul*mt%mod;
node[rc].tag_add=1LL*node[rc].tag_add*mt%mod;
node[rc].sum=1LL*node[rc].sum*mt%mod;
inc(node[rc].tag_add,at); inc(node[rc].sum,1LL*rtot*at%mod);
node[now].tag_mul=1; node[now].tag_add=0;
}
}
public:
inline void build(int now,int l,int r)
{
if (l==r) return (void)(node[now].sum=a[l]); int mid=l+r>>1;
build(now<<1,l,mid); build(now<<1|1,mid+1,r); pushup(now);
}
#define O beg,end
inline void modify_mul(int now,int l,int r,int beg,int end,int val)
{
if (l>=beg&&r<=end)
{
node[now].tag_mul=1LL*node[now].tag_mul*val%mod;
node[now].tag_add=1LL*node[now].tag_add*val%mod;
node[now].sum=1LL*node[now].sum*val%mod; return;
}
int mid=l+r>>1; pushdown(now,mid-l+1,r-mid);
if (beg<=mid) modify_mul(now<<1,l,mid,O,val);
if (end>mid) modify_mul(now<<1|1,mid+1,r,O,val);
pushup(now);
}
inline void modify_add(int now,int l,int r,int beg,int end,int val)
{
if (l>=beg&&r<=end)
{
inc(node[now].sum,1LL*val*(r-l+1)%mod);
inc(node[now].tag_add,val); return;
}
int mid=l+r>>1; pushdown(now,mid-l+1,r-mid);
if (beg<=mid) modify_add(now<<1,l,mid,O,val);
if (end>mid) modify_add(now<<1|1,mid+1,r,O,val);
pushup(now);
}
inline int query(int now,int l,int r,int beg,int end)
{
if (l>=beg&&r<=end) return node[now].sum;
int mid=l+r>>1,ret=0; pushdown(now,mid-l+1,r-mid);
if (beg<=mid) inc(ret,query(now<<1,l,mid,O));
if (end>mid) inc(ret,query(now<<1|1,mid+1,r,O));
return ret;
}
#undef pushup
#undef O
}T;

P3384 【模板】树链剖分

这个东西大力码就好了,1A没什么问题。

class Tree_Chain_Dissection
{
private:
int dep[N],size[N],father[N],top[N],id[N],son[N],idx;
inline void swap(int &x,int &y)
{
int t=x; x=y; y=t;
}
public:
#define to e[i].to
inline void DFS1(int now,int fa)
{
dep[now]=dep[fa]+1; size[now]=1; int res=-1;
for (RI i=head[now];i;i=e[i].nxt) if (to!=fa)
{
DFS1(to,now); size[now]+=size[to]; father[to]=now;
if (size[to]>res) res=size[to],son[now]=to;
}
}
inline void DFS2(int now,int topf)
{
s[id[now]=++idx]=now; top[now]=topf;
if (son[now]) DFS2(son[now],topf);
for (RI i=head[now];i;i=e[i].nxt)
if (to!=father[now]&&to!=son[now]) DFS2(to,to);
}
#undef to
inline void modify(int x,int y,int val)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
T.modify(1,1,n,id[top[x]],id[x],val);
x=father[top[x]];
}
if (dep[x]<dep[y]) swap(x,y);
T.modify(1,1,n,id[y],id[x],val);
}
inline int query(int x,int y)
{
int ret=0; while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
inc(ret,T.query(1,1,n,id[top[x]],id[x]));
x=father[top[x]];
}
if (dep[x]<dep[y]) swap(x,y);
inc(ret,T.query(1,1,n,id[y],id[x]));
return ret;
}
inline void updata(int x,int y)
{
T.modify(1,1,n,id[x],id[x]+size[x]-1,y);
}
inline int ask(int x)
{
return T.query(1,1,n,id[x],id[x]+size[x]-1);
}
}L;

P3834 【模板】可持久化线段树 1(主席树)

刚开始没读排名调了好久。。。第一次发现主席树原来不用写build

class President_Tree
{
private:
#define P 18
struct Segment
{
int ch[2],size;
}node[N*P]; int tot;
#define lc(x) node[x].ch[0]
#define rc(x) node[x].ch[1]
public:
inline void modify(int &now,int lst,int l,int r,int id)
{
node[now=++tot]=node[lst]; ++node[now].size;
if (l==r) return; int mid=l+r>>1;
if (id<=mid) modify(lc(now),lc(lst),l,mid,id);
else modify(rc(now),rc(lst),mid+1,r,id);
}
inline int query(int lst,int now,int l,int r,int rk)
{
if (l==r) return l; int dlt=node[lc(now)].size-node[lc(lst)].size,mid=l+r>>1;
if (rk<=dlt) return query(lc(lst),lc(now),l,mid,rk);
else return query(rc(lst),rc(now),mid+1,r,rk-dlt);
}
#undef P
#undef lc
#undef rc
}T;

P3369 【模板】普通平衡树

10号晚上打Treap打到近11点也没调出来。。。

11号晚上改掉的。然而并没有考数据结构

class Treap
{
private:
struct treap
{
int ch[2],size,cnt,val,dat;
treap(int Lc=0,int Rc=0,int Size=0,int Cnt=0,int Val=0,int Dat=0)
{
ch[0]=Lc; ch[1]=Rc; size=Size; cnt=Cnt; val=Val; dat=Dat;
}
}node[N]; int tot,seed;
#define lc(x) node[x].ch[0]
#define rc(x) node[x].ch[1]
inline int rand(void)
{
return seed=(int)seed*482711LL%2147483647;
}
inline int create(int val)
{
node[++tot]=treap(0,0,1,1,val,rand()); return tot;
}
inline void pushup(int now)
{
node[now].size=node[lc(now)].size+node[rc(now)].size+node[now].cnt;
}
inline void rotate(int &now,int d)
{
int t=node[now].ch[d^1]; node[now].ch[d^1]=node[t].ch[d];
node[t].ch[d]=now; now=t; pushup(node[now].ch[d]); pushup(now);
}
public:
int rt;
Treap() { seed=233; }
inline void init(void)
{
rt=create(-INF); rc(rt)=create(INF); pushup(rt);
}
inline void insert(int &now,int val)
{
if (!now) return (void)(now=create(val));
if (val==node[now].val) return (void)(++node[now].cnt,pushup(now));
int d=val<node[now].val?0:1; insert(node[now].ch[d],val);
if (node[node[now].ch[d]].dat>node[now].dat) rotate(now,d^1);
pushup(now);
}
inline void remove(int &now,int val)
{
if (!now) return; if (val==node[now].val)
{
if (node[now].cnt>1) return (void)(--node[now].cnt,pushup(now));
if (lc(now)||rc(now))
{
if (!rc(now)||node[lc(now)].dat>node[rc(now)].dat)
rotate(now,1),remove(rc(now),val); else
rotate(now,0),remove(lc(now),val);
pushup(now);
} else now=0; return;
}
if (val<node[now].val) remove(lc(now),val); else remove(rc(now),val); pushup(now);
}
inline int get_rk(int now,int val)
{
if (!now) return 0;
if (val==node[now].val) return node[lc(now)].size+1; else
if (val<node[now].val) return get_rk(lc(now),val); else
return node[lc(now)].size+node[now].cnt+get_rk(rc(now),val);
}
inline int get_val(int now,int rk)
{
if (!now) return INF;
if (rk<=node[lc(now)].size) return get_val(lc(now),rk); else
if (rk<=node[lc(now)].size+node[now].cnt) return node[now].val;
else return get_val(rc(now),rk-node[lc(now)].size-node[now].cnt);
}
inline int get_pre(int now,int val,int pre=0)
{
while (now) if (node[now].val<val) pre=node[now].val,now=rc(now);
else now=lc(now); return pre;
}
inline int get_nxt(int now,int val,int nxt=0)
{
while (now) if (node[now].val>val) nxt=node[now].val,now=lc(now);
else now=rc(now); return nxt;
}
#undef lc
#undef rc
}T;

Postscript

时间太紧张了才给自己留了两天,刷了一半左右

感觉今年板子刷的没什么用呵?果然背过的都不考

退役钦定QWQ感觉放松心态吧

相关文章