随机复习清单
感觉,什么板子都不会写了。
其实大部分都直接去看对应博客就行了吧,这里随机写一点一定要背的。
1. 杂项
1.0 注意事项
taskkill /f /im _.exe 删掉发癫的 exe。
检查空间,0x3f3f3f3f 比 2e9 小,不建议关 ll,卡常的话再说。
调题的时候只目测一遍,一定要节省时间,最多看一遍,没调出来就打拍子,之前打的暴力就有用了,开题没会先写暴力是对的吧。
会了的话可以先看后面的,有空了再回来挂牌子,感觉 ccf 大样例不会那么弱。
可以在纸上或者代码里面打注释,把所有观察写进去,防止后面写着写着忘了。
1.1 编译命令
哎这怎么没了。
-std=c++14 -O2 -Wall -Wl,--stack=2147483647 -Wshadow -Wextra -fno-ms-extensions
1.2 缺省源
更新一些东西让 devc 也可以编译。
点击查看
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define pr putchar(10)
#define fi first
#define se second
#define pp putchar(' ')
#define pii pair<ll,ll>
#define tri tuple<ll,ll,ll>
#define gt(k,x) (get<k>(x))
#define pdi pair<double,ll>
#define mem(aa,bb) memset(aa,bb,sizeof(aa))
#define fo(a,i,b) for(ll i = (a) ; i <= (b) ; ++ i )
#define Fo(a,i,b) for(ll i = (a) ; i >= (b) ; -- i )
#define pb push_back
#define eb emplace_back
#define bct __builtin_popcount
#define mk make_pair
#define IT iterator
#define all(x) x.begin(),x.end()
#define lbd lower_bound
#define ubd upper_bound
#define lowbit(x) ((x)&(-(x)))
#define gb(x,i) (((x)>>i)&1)
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
// #define deb(a...) [&](auto...b){char s[]=" , ,"#a;strtok(s,",");((cerr<<strtok(0,",")<<"="<<b<<"; "),...)<<endl;}(__LINE__,a)
//#pragma GCC optimize(2)
using namespace std;
bool ST;
typedef long long i64;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
// typedef int ll;
typedef long long ll;
// typedef __int128 ll;
// #define getchar getchar_unlocked
// #define putchar putchar_unlocked
const ll mod=1e9+7;
template <class T> inline bool ckmn(T &a,T b){return a>b?a=b,1:0;}
template <class T> inline bool ckmx(T &a,T b){return a<b?a=b,1:0;}
template <class T> inline void _A(T &x,T y){x=(x+y>=mod?x+y-mod:x+y);}
template <class T> inline void _M(T &x,T y){x=1ll*x*y%mod;}
template <class T> inline T A_(T x,T y){return (x+y>=mod?x+y-mod:x+y);}
template <class T> inline T M_(T x,T y){return 1ll*x*y%mod;}
template <class T> inline void read(T &s)
{
s=0;int f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))s=(s<<3)+(s<<1)+(c^48),c=getchar();s*=f;return;
}
template <class T> inline void wr(T x)
{
if(x<0)putchar('-'),x=-x;int buf[21],top=0;while(x)buf[++top]=x%10,x/=10;
if(!top)buf[++top]=0;while(top)putchar(buf[top--]^'0');return;
}
template <class T, class ...A> inline void read(T &x,A &...a){read(x);read(a...);}
template <class T, class ...A> inline bool ckmn(T &x,T y,A ...a){return ckmn(x,y)|ckmn(x,a...);}
template <class T, class ...A> inline bool ckmx(T &x,T y,A ...a){return ckmx(x,y)|ckmx(x,a...);}
template <class T, class ...A> inline void _A(T &x,T y,A ...a){_A(x,y),_A(x,a...);}
template <class T, class ...A> inline void _M(T &x,T y,A ...a){_M(x,y),_M(x,a...);}
template <class T, class ...A> inline T A_(T x,T y,A ...a){return A_(A_(x,y),a...);}
template <class T, class ...A> inline T M_(T x,T y,A ...a){return M_(M_(x,y),a...);}
template<class... T> void deb_(int line, const T&... v){cerr<<"LINE "<<line<<" =";int _[]={0,(cerr<<' '<<v,0)...};(void)_;cerr<<'\n';}
#define deb(...) deb_(__LINE__, __VA_ARGS__)
const ll _N=1e6+5;ll Pre[_N],Inv[_N];
inline ll qpow(ll a,ll b){return !b?1ll:M_(1ll*qpow(M_(a,a),b>>1ll),((b&1ll)?a:1ll));}
inline ll C(ll n,ll m){return (n<m||n<0||m<0)?0ll:M_(Pre[n],Inv[m],Inv[n-m]);}
inline void InitC(ll n){Pre[0]=1;fo(1,i,n) Pre[i]=M_(Pre[i-1],i);Inv[n]=qpow(Pre[n],mod-2);Fo(n-1,i,1) Inv[i]=M_(Inv[i+1],(i+1));Inv[0]=1;}
const ll N=1e6+5,M=1e5+5;
bool ED;
signed main(){
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
2. 数据结构
2.1 FHQ
记得按什么分裂,按值分裂和按大小分裂本质不同
普通平衡树
const ll N=1e6+5,M=1e5+5;
ll n,root,tot,op,x;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
struct FHQTreap{ll l,r,sum,siz;u32 val;}t[N];
#define rt t[x]
#define ls t[t[x].l]
#define rs t[t[x].r]
inline void ps(ll x){rt.siz=ls.siz+rs.siz+1;}
inline void mkn(ll k){t[++tot]={0,0,k,1,rnd()};}
inline void sp(ll x,ll k,ll &u,ll &v){if(!x) return u=v=0,void();if(rt.sum<=k) u=x,sp(rt.r,k,t[u].r,v);else v=x,sp(rt.l,k,u,t[v].l);ps(x);}
inline ll mrg(ll x,ll y){if(!x||!y) return x|y;if(t[x].val>t[y].val) return t[x].r=mrg(t[x].r,y),ps(x),x;return t[y].l=mrg(x,t[y].l),ps(y),y;}
inline void ins(ll k){mkn(k);ll x,y;sp(root,k,x,y),root=mrg(mrg(x,tot),y);}
inline void del(ll k){ll x,y,z;sp(root,k,y,z),sp(y,k-1,x,y),y=mrg(t[y].l,t[y].r);root=mrg(mrg(x,y),z);}
inline ll kth(ll x,ll k){if(ls.siz+1==k) return x;if(k<=ls.siz) return kth(rt.l,k);else return kth(rt.r,k-ls.siz-1);}
inline ll rnk(ll x,ll k){if(!x) return 0;if(k>=rt.sum) return rnk(rt.r,k)+ls.siz+1;return rnk(rt.l,k);}
inline ll gtp(ll x,ll k){if(!x) return -inf;if(rt.sum<k) return max(rt.sum,gtp(rt.r,k));return gtp(rt.l,k);}
inline ll gts(ll x,ll k){if(!x) return inf;if(rt.sum>k) return min(rt.sum,gts(rt.l,k));return gts(rt.r,k);}
bool ED;
signed main(){
read(n);fo(1,i,n)
{
read(op,x);
if(op==1) ins(x);
if(op==2) del(x);
if(op==3) wr(rnk(root,x-1)+1),pr;
if(op==4) wr(t[kth(root,x)].sum),pr;
if(op==5) wr(gtp(root,x)),pr;
if(op==6) wr(gts(root,x)),pr;
}
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
可持久化也太巨大了,感觉没有理由能写出来。
可持久化
const ll N=3.6e6+5,M=1e5+5;
ll n,q,opt,l1,l2,r1,r2,k,x,root,tot,las;vector<ll> vec;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
struct FHQTreap{ll l,r,num,sum,siz,cov,rev,lz;u32 val;}t[N];
#define rt t[x]
#define ls t[t[x].l]
#define rs t[t[x].r]
inline ll mkn(ll x){++tot;t[tot]={0,0,x,x,1,-1,0,0,rnd()};return tot;}
inline ll cop(ll y){if(!y) return 0;++tot;t[tot]=t[y];return tot;}
inline void Mdf(ll x,ll k){if(!x)return;_A(rt.sum,M_(k,rt.siz)),_A(rt.num,k);if(rt.cov!=-1) _A(rt.cov,k);else _A(rt.lz,k);}
inline void Cov(ll x,ll k){if(!x)return;rt.sum=M_(k,rt.siz),rt.num=k;rt.lz=0,rt.cov=k;}
inline void Rev(ll x){if(!x)return;rt.rev^=1;}
inline void pd(ll x){if(rt.lz||rt.cov!=-1||rt.rev) rt.l=cop(rt.l),rt.r=cop(rt.r);if(rt.lz) Mdf(rt.l,rt.lz),Mdf(rt.r,rt.lz),rt.lz=0;if(rt.cov!=-1) Cov(rt.l,rt.cov),Cov(rt.r,rt.cov),rt.cov=-1;if(rt.rev) swap(rt.l,rt.r),Rev(rt.l),Rev(rt.r),rt.rev=0;}
inline void ps(ll x){if(x) rt.siz=ls.siz+rs.siz+1,rt.sum=A_(ls.sum,rs.sum,rt.num);}
inline void sp(ll x,ll k,ll &u,ll &v){if(!x) return u=v=0,void();pd(x);if(ls.siz+1<=k) u=cop(x),sp(rt.r,k-ls.siz-1,t[u].r,v),ps(u);else v=cop(x),sp(rt.l,k,u,t[v].l),ps(v);}
inline ll mrg(ll u,ll v){if(!u||!v) return u|v;if(t[u].val>t[v].val) return pd(u),u=cop(u),t[u].r=mrg(t[u].r,v),ps(u),u;return pd(v),v=cop(v),t[v].l=mrg(u,t[v].l),ps(v),v;}
inline ll build(ll l,ll r){if(l>r) return 0;ll mid=l+r>>1,nw=mkn(vec[mid]);t[nw].l=build(l,mid-1),t[nw].r=build(mid+1,r);ps(nw);return nw;}
inline ll qry(ll l,ll r){ll x,y,z,ans;sp(root,r,y,z),sp(y,l-1,x,y),ans=t[y].sum;root=mrg(mrg(x,y),z);return ans;}
inline void cov(ll l,ll r,ll k){ll x,y,z;sp(root,r,y,z),sp(y,l-1,x,y),y=cop(y),Cov(y,k),root=mrg(mrg(x,y),z);}
inline void upd(ll l,ll r,ll k){ll x,y,z;sp(root,r,y,z),sp(y,l-1,x,y),y=cop(y),Mdf(y,k),root=mrg(mrg(x,y),z);}
inline void rev(ll l,ll r){ll x,y,z;sp(root,r,y,z),sp(y,l-1,x,y),y=cop(y),Rev(y),root=mrg(mrg(x,y),z);}
inline void cpy(ll l1,ll r1,ll l2,ll r2)
{
ll fl=0,a,b,c,d,e;if(l1>r2) swap(l1,l2),swap(r1,r2),fl=1;
sp(root,r2,d,e),sp(d,l2-1,c,d),sp(c,r1,b,c),sp(b,l1-1,a,b);
if(!fl) d=cop(b);else b=cop(d);root=mrg(mrg(mrg(mrg(a,b),c),d),e);
}
inline void swp(ll l1,ll r1,ll l2,ll r2)
{
ll fl=0,a,b,c,d,e;if(l1>r2) swap(l1,l2),swap(r1,r2),fl=1;
sp(root,r2,d,e),sp(d,l2-1,c,d),sp(c,r1,b,c),sp(b,l1-1,a,b);
root=mrg(mrg(mrg(mrg(a,d),c),b),e);
}
inline void dfs(ll x){if(!x) return;pd(x);dfs(rt.l),vec.pb(t[x].num),dfs(rt.r);}
bool ED;
signed main(){
read(n,q);fo(1,i,n) read(x),vec.pb(x);root=build(0,n-1);
fo(1,i,q)
{
read(opt);
if(opt==1) read(l1,r1),wr(las=qry(l1^las,r1^las)),pr;
if(opt==2) read(l1,r1,k),cov(l1^las,r1^las,k^las);
if(opt==3) read(l1,r1,k),upd(l1^las,r1^las,k^las);
if(opt==4) read(l1,r1,l2,r2),cpy(l1^las,r1^las,l2^las,r2^las);
if(opt==5) read(l1,r1,l2,r2),swp(l1^las,r1^las,l2^las,r2^las);
if(opt==6) read(l1,r1),rev(l1^las,r1^las);
if(tot>2.8e6){vec.clear();dfs(root);tot=root=0;root=build(0,n-1);}
}
vec.clear();dfs(root);for(ll i:vec) wr(i),pp;pr;
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
带交合并注意要处理相同值,每个题对相同值的处理可能都不同。
例题 P11622
带交合并
inline ll Merge(ll x,ll y)
{
if(!x||!y) return x|y;if(t[x].val>t[y].val) swap(x,y);pd(x),pd(y);
ll L1=t[x].l,R1=t[x].r,L2=0,R2=0,equ=0;sp(y,t[x].sum-1,L2,R2),sp(R2,t[x].sum,equ,R2);
if(equ) Link(equ,x);t[x].l=Merge(L1,L2),t[x].r=Merge(R1,R2);return ps(x),x;
}
2.2 LCT
本质好背的吧,记得多写几遍。
这个如果写错了真会超级无敌难调吧。
LCT
const ll N=1e6+5,M=1e5+5;
ll n,m,op,x,y,a[N],sum[N],lz[N],st[N],s[N][2],fa[N];
#define ls s[x][0]
#define rs s[x][1]
inline void ps(ll x){sum[x]=sum[ls]^sum[rs]^a[x];}
inline bool nr(ll x){return s[fa[x]][0]==x||s[fa[x]][1]==x;}
inline void rev(ll x){if(x) swap(ls,rs),lz[x]^=1;}
inline void pd(ll x){if(lz[x]) rev(ls),rev(rs),lz[x]=0;}
inline void rtt(ll x)
{
ll y=fa[x],z=fa[y],k=s[y][1]==x,w=s[x][!k];
if(nr(y)) s[z][s[z][1]==y]=x;s[y][k]=w,s[x][!k]=y;
if(w) fa[w]=y;fa[y]=x,fa[x]=z,ps(y),ps(x);
}
inline void sp(ll x)
{
ll y=x,z=0;st[++z]=x;while(nr(y)) st[++z]=y=fa[y];while(z) pd(st[z--]);
while(nr(x)) y=fa[x],z=fa[y],nr(y)?rtt((s[y][1]==x)^(s[z][1]==y)?x:y),1:1,rtt(x);
}
inline void ac(ll x){for(ll y=0;x;x=fa[y=x]) sp(x),rs=y,ps(x);}
inline void mr(ll x){ac(x),sp(x),rev(x);}
inline void sp(ll x,ll y){mr(x),ac(y),sp(y);}
inline ll fr(ll x){ac(x),sp(x);while(ls) x=ls,pd(x);sp(x);return x;}
inline void lk(ll x,ll y){mr(x);if(fr(y)!=x) fa[x]=y;}
inline void ct(ll x,ll y){mr(x);if(fr(y)==x&&fa[y]==x&&!s[y][0]) s[x][1]=fa[y]=0,ps(x);}
bool ED;
signed main(){
read(n,m);fo(1,i,n) read(a[i]);
fo(1,i,m)
{
read(op,x,y);
if(op==0) sp(x,y),wr(sum[y]),pr;
if(op==1) lk(x,y);
if(op==2) ct(x,y);
if(op==3) sp(x),a[x]=y,sp(x);
}
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
2.3 KDT
本质平衡树,nth_element 可以把复杂度分析到 \(O(n^{\frac{k-1}{k}})\),方差建树可能会更快,具体就是每次找每一维方差最大的那个。
可以拿来做二维最值的乱搞,一般不好卡。
KDT
const ll N=1.5e5+5,M=1e3+5;
#define qua tuple<ll,ll,ll,ll>
ll K,m,op,xx[3],yy[3],zz,las,siz;
struct KDT
{
struct Tree{i32 l,r;ll xl,xr,yl,yr,zl,zr,sum,lz;};
vector<Tree> tree;vector<qua> p;
#define rt tree[root]
#define ls tree[root<<1]
#define rs tree[root<<1|1]
inline void pushup(i32 root)
{
rt.xl=min(ls.xl,rs.xl),rt.xr=max(ls.xr,rs.xr),
rt.yl=min(ls.yl,rs.yl),rt.yr=max(ls.yr,rs.yr),
rt.zl=min(ls.zl,rs.zl),rt.zr=max(ls.zr,rs.zr),
rt.sum=ls.sum+rs.sum;
}
inline void mdf(i32 root,ll k){rt.sum+=(rt.r-rt.l+1)*k,rt.lz+=k;}
inline void pd(i32 root){if(rt.lz) mdf(root<<1,rt.lz),mdf(root<<1|1,rt.lz),rt.lz=0;}
inline void build(i32 root,i32 l,i32 r,ll op)
{
rt.l=l,rt.r=r;if(l==r) return rt={l,r,gt(0,p[l]),gt(0,p[l]),gt(1,p[l]),gt(1,p[l]),gt(2,p[l]),gt(2,p[l]),gt(3,p[l]),0},void();ll mid=l+r>>1;
nth_element(p.begin()+l,p.begin()+mid,p.begin()+r+1,[&](qua x,qua y){return op==0?gt(0,x)<gt(0,y):(op==1?gt(1,x)<gt(1,y):gt(2,x)<gt(2,y));});
op=(op+1)%K,build(root<<1,l,mid,op),build(root<<1|1,mid+1,r,op),pushup(root);
}
inline void upd(i32 root,ll xl,ll xr,ll yl,ll yr,ll zl,ll zr,ll k)
{
if(xl>rt.xr||xr<rt.xl||yl>rt.yr||yr<rt.yl||zl>rt.zr||zr<rt.zl) return;i32 l=rt.l,r=rt.r,mid=l+r>>1;
if(xl<=rt.xl&&xr>=rt.xr&&yl<=rt.yl&&yr>=rt.yr&&zl<=rt.zl&&zr>=rt.zr) return mdf(root,k);pd(root);
if(l==r)return;upd(root<<1,xl,xr,yl,yr,zl,zr,k),upd(root<<1|1,xl,xr,yl,yr,zl,zr,k),rt.sum=ls.sum+rs.sum;
}
inline ll qry(i32 root,ll xl,ll xr,ll yl,ll yr,ll zl,ll zr)
{
if(xl>rt.xr||xr<rt.xl||yl>rt.yr||yr<rt.yl||zl>rt.zr||zr<rt.zl) return 0;i32 l=rt.l,r=rt.r,mid=l+r>>1;
if(xl<=rt.xl&&xr>=rt.xr&&yl<=rt.yl&&yr>=rt.yr&&zl<=rt.zl&&zr>=rt.zr) return rt.sum;pd(root);
return l!=r?qry(root<<1,xl,xr,yl,yr,zl,zr)+qry(root<<1|1,xl,xr,yl,yr,zl,zr):0ll;
}
inline void cls(i32 root){i32 l=rt.l,r=rt.r,mid=l+r>>1;if(l==r) return gt(3,p[l])=rt.sum,void();pd(root);cls(root<<1),cls(root<<1|1);}
}t[18];
inline void ins(ll x,ll y,ll z,ll k)
{
vector<qua> vec;vec.pb({x,y,z,k});fo(0,i,__lg(lowbit(siz+1))-1){t[i].cls(1);for(qua i:t[i].p) vec.pb(i);t[i].p.clear(),t[i].tree.clear();}
++siz;ll id=__lg(lowbit(siz)),len=vec.size();swap(vec,t[id].p),vec.clear(),t[id].tree.resize(len<<1),t[id].build(1,0,len-1,0);
}
inline void upd(ll xl,ll xr,ll yl,ll yr,ll zl,ll zr,ll k){for(i32 i=siz,id;i;i-=lowbit(i)) id=__lg(lowbit(i)),t[id].upd(1,xl,xr,yl,yr,zl,zr,k);}
inline ll qry(ll xl,ll xr,ll yl,ll yr,ll zl,ll zr){ll ans=0;for(i32 i=siz,id;i;i-=lowbit(i)) id=__lg(lowbit(i)),ans+=t[id].qry(1,xl,xr,yl,yr,zl,zr);return ans;}
signed main(){
read(K,m);fo(1,i,m)
{
read(op);
if(op==1)
{
fo(0,i,K-1) read(xx[i]),xx[i]^=las;read(zz),zz^=las;
ins(xx[0],xx[1],xx[2],zz);
}
if(op==2)
{
fo(0,i,K-1) read(xx[i]);fo(0,i,K-1) read(yy[i]);read(zz);
fo(0,i,K-1) xx[i]^=las,yy[i]^=las;zz^=las;
upd(xx[0],yy[0],xx[1],yy[1],xx[2],yy[2],zz);
}
if(op==3)
{
fo(0,i,K-1) read(xx[i]),xx[i]^=las;fo(0,i,K-1) read(yy[i]),yy[i]^=las;
wr(las=qry(xx[0],yy[0],xx[1],yy[1],xx[2],yy[2])),pr;
}
}
return 0;
}
2.4 点分树
怎么,这个真忘了怎么写了,noi 警示后人来的?
大概就是,建出点分治过程中形成的树,这棵树和原树的父子没有关系,但是原树上两点的 LCA 一定在点分树的路径上。
不能用父子关系维护信息。
点分树
const ll N=1e5+5,M=1e5+5;
ll n,m,a[N],beg,maxn[N],siz[N],dep[N],fa[N],son[N],top[N],id[N],w[N],cnt,sum,vis[N],f[N];vector<ll> g[N];
struct SGT
{
ll rot[N],cnt;
struct SegMent_Tree{ll l,r,sum;}tree[N*300];
#define rt tree[root]
#define ls tree[tree[root].l]
#define rs tree[tree[root].r]
inline void upd(ll &root,ll l,ll r,ll x,ll k)
{
if(!root) root=++cnt;rt.sum+=k;if(l==r) return;
ll mid=l+r>>1;if(x<=mid) upd(rt.l,l,mid,x,k);else upd(rt.r,mid+1,r,x,k);
}
inline ll ask(ll root,ll l,ll r,ll x,ll y)
{
if(!root||x>y) return 0;if(x<=l&&y>=r) return rt.sum;
ll mid=l+r>>1,ans=0;if(x<=mid) ans=ask(rt.l,l,mid,x,y);if(y>mid) ans+=ask(rt.r,mid+1,r,x,y);return ans;
}
}t1,t2;
inline void dfs1(ll x,ll fat,ll depth){fa[x]=fat,dep[x]=depth,siz[x]=1;for(ll y:g[x]){if(y==fat)continue;dfs1(y,x,depth+1);siz[x]+=siz[y];if(siz[y]>siz[son[x]]) son[x]=y;ckmx(maxn[x],siz[y]);}ckmx(maxn[x],n-siz[x]);if(maxn[x]<maxn[beg]) beg=x;}
inline void dfs2(ll x,ll nowtop){top[x]=nowtop,id[x]=++cnt,w[cnt]=x;if(!son[x])return;dfs2(son[x],nowtop);for(ll y:g[x]) if(y!=son[x]&&y!=fa[x]) dfs2(y,y);}
inline void dfs(ll x,ll fa){siz[x]=1,maxn[x]=0;for(ll y:g[x]) if(y!=fa&&!vis[y]) dfs(y,x),siz[x]+=siz[y],ckmx(maxn[x],siz[y]);ckmx(maxn[x],sum-siz[x]);if(maxn[x]<maxn[beg]) beg=x;}
inline void dfz(ll x,ll fa){vis[x]=1;for(ll y:g[x]) if(!vis[y]&&y!=fa) beg=0,sum=siz[y],dfs(y,0),dfs(beg,0),f[beg]=x,dfz(beg,x);}
inline ll LCA(ll x,ll y){while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];return dep[x]<dep[y]?x:y;}
inline ll dis(ll x,ll y){if(!x||!y) return 0;return dep[x]+dep[y]-2*dep[LCA(x,y)];}
inline void mdf(ll x,ll u,ll k)
{
if(!x) return;t1.upd(t1.rot[x],0,n,dis(u,x),k);
if(f[x]) t2.upd(t2.rot[x],0,n,dis(u,f[x]),k);mdf(f[x],u,k);
}
inline ll qry(ll x,ll u,ll v,ll k)
{
if(!x) return 0;ll num=t1.ask(t1.rot[x],0,n,0,k-dis(x,u))-t2.ask(t2.rot[v],0,n,0,k-dis(x,u));
return num+qry(f[x],u,x,k);
}
inline void solve()
{
read(n,m);fo(1,i,n) read(a[i]);
ll u,v;fo(1,i,n-1) read(u,v),g[u].pb(v),g[v].pb(u);
maxn[beg]=inf,sum=n;dfs1(1,0,1),dfs2(1,1),dfs(beg,0),dfz(beg,0);
ll las=0,op,x,y;fo(1,i,n) mdf(i,i,a[i]);fo(1,i,m)
read(op,x,y),x^=las,y^=las,op?mdf(x,x,y-a[x]),a[x]=y,void():(wr(las=qry(x,x,0,y)),pr,void());
}
bool ED;
signed main(){
#ifdef ONLINE_JUDGE
// freopen("0.in","r",stdin);
// freopen("0.out","w",stdout);
double st=clock();
#endif
int T=1;while(T--) solve();
#ifdef ONLINE_JUDGE
double ed=clock();
cerr<<endl;cerr<<"Time: "<<ed-st<<" ms\n";
cerr<<"Memory: "<<abs(&ST-&ED)/1024.0/1024.0<<" MB\n";
#endif
return 0;
}
2.5 线段树历史和
当然可以拿矩阵推,而且并不难推,但是这个最简单常数肯定越小越好,看 LOJ 板子。
历史和
const ll N=1e6+5,M=2e4+5;
ll n,m,a[N];
struct SGT{ll l,r,sum,hsum,lz,hlz,up;}tree[N<<2];
#define rt tree[root]
#define ls tree[root<<1]
#define rs tree[root<<1|1]
inline void pushup(ll root){rt.sum=ls.sum+rs.sum;rt.hsum=ls.hsum+rs.hsum;}
inline void build(ll root,ll l,ll r){rt.l=l,rt.r=r;if(l==r) return rt.sum=rt.hsum=a[l],void();ll mid=l+r>>1;build(root<<1,l,mid),build(root<<1|1,mid+1,r);pushup(root);}
inline void mdf(ll root,ll lz,ll hlz,ll up)
{
rt.hsum+= rt.sum*up+hlz*(rt.r-rt.l+1);
rt.sum += lz*(rt.r-rt.l+1);
rt.hlz += hlz+up*rt.lz;
rt.up += up,rt.lz += lz;
}
inline void pd(ll root,ll l,ll r){ll lz=rt.lz,hlz=rt.hlz,up=rt.up;mdf(root<<1,lz,hlz,up),mdf(root<<1|1,lz,hlz,up),rt.lz=rt.hlz=rt.up=0;}
inline void upd(ll root,ll l,ll r,ll x,ll y,ll k){if(x<=l&&y>=r) return mdf(root,k,0,0);ll mid=l+r>>1;pd(root,l,r);if(x<=mid) upd(root<<1,l,mid,x,y,k);if(y>mid) upd(root<<1|1,mid+1,r,x,y,k);pushup(root);}
inline ll ask(ll root,ll l,ll r,ll x,ll y){if(x<=l&&y>=r) return rt.hsum;ll mid=l+r>>1,ans=0;pd(root,l,r);if(x<=mid) ans=ask(root<<1,l,mid,x,y);if(y>mid) ans+=ask(root<<1|1,mid+1,r,x,y);return ans;}
signed main(){
read(n,m);fo(1,i,n) read(a[i]);build(1,1,n);
fo(1,i,m)
{
ll op,l,r,k;read(op,l,r);
if(op==1) read(k),upd(1,1,n,l,r,k);
if(op==2) wr(ask(1,1,n,l,r)),pr;mdf(1,0,0,1);
}
return 0;
}
2.6 莫队
看看怎么排序的()
3. 图论
3.1 网络流
一般都是 Dinic 吧。我真不会写网络流。。。
Dinic
const ll N=1e6+5,M=1e5+5;
ll n,m,s,t,u,v,w,head[N],tot=1,ans,dis[N],cur[N];
struct Edge{ll ver,nxt,w;}g[N];
inline void add(ll u,ll v,ll w){g[++tot]={v,head[u],w},head[u]=tot;}
inline bool bfs()
{
fo(1,i,n) dis[i]=inf;dis[s]=0,cur[s]=head[s];queue<ll> q;q.push(s);
while(q.size())
{
ll x=q.front();q.pop();
for(ll i=head[x];i;i=g[i].nxt)
{
ll y=g[i].ver;if(dis[y]!=inf||!g[i].w) continue;
dis[y]=dis[x]+1,q.push(y),cur[y]=head[y];if(y==t) return 1;
}
}return 0;
}
inline ll dfs(ll x,ll lim)
{
if(x==t) return lim;ll sum=0;
for(ll i=cur[x];i&&lim;i=g[i].nxt)
{
cur[x]=i;ll y=g[i].ver;if(dis[y]!=dis[x]+1||!g[i].w) continue;
ll k=dfs(y,min(lim,g[i].w));if(!k) dis[y]=inf;g[i].w-=k,g[i^1].w+=k,lim-=k,sum+=k;
}return sum;
}
signed main(){
read(n,m,s,t);fo(1,i,m) read(u,v,w),add(u,v,w),add(v,u,0);
while(bfs()) ans+=dfs(s,inf);wr(ans),pr;
return 0;
}
费用流就把 bfs 换成 spfa 或者 dij,好像还有更牛的网络流,但是我不会啊。
费用流
const ll N=1e6+5,M=1e5+5;
ll n,m,s,t,head[N],tot=1,dis[N],vis[N],cur[N],ans,ans1;
struct Edge{ll ver,nxt,w,c;}e[N];
inline void add(ll u,ll v,ll w,ll c){e[++tot]={v,head[u],w,c};head[u]=tot;}
inline bool spfa()
{
queue<ll> q;fo(1,i,n) dis[i]=inf,vis[i]=0;dis[s]=0,cur[s]=head[s],vis[s]=1,q.push(s);
while(q.size())
{
ll x=q.front();q.pop();vis[x]=0;
for(ll i=head[x];i;i=e[i].nxt)
{
ll y=e[i].ver;if(!e[i].w||dis[y]<=dis[x]+e[i].c) continue;
dis[y]=dis[x]+e[i].c,cur[y]=head[y];if(!vis[y]) q.push(y),vis[y]=1;
}
}return dis[t]!=inf;
}
inline ll dfs(ll x,ll lim)
{
if(x==t) return lim;ll sum=0;vis[x]=1;
for(ll i=cur[x];i&&lim;i=e[i].nxt)
{
ll y=e[i].ver;cur[x]=i;if(vis[y]||!e[i].w||dis[y]!=dis[x]+e[i].c) continue;
ll k=dfs(y,min(lim,e[i].w));if(!k) dis[y]=inf;e[i].w-=k,e[i^1].w+=k,sum+=k,lim-=k,ans1+=k*e[i].c;
}return vis[x]=0,sum;
}
signed main(){
read(n,m,s,t);ll u,v,w,c;fo(1,i,m) read(u,v,w,c),add(u,v,w,c),add(v,u,0,-c);
while(spfa()) ans+=dfs(s,inf);wr(ans),pp,wr(ans1),pr;
return 0;
}
3.2 树哈希
这个好像真得稍微背一下那个代价函数。
树哈希
const ll N=1e6+5,M=1e3+5;
const u64 mask=mt19937_64(time(0))();
ll m,n,u,v,fa[N],rt;vector<ll> G[N];u64 f[N],g[N],ans;unordered_map<u64,ll> mp;vector<u64> vec;
multiset<u64> st[N];
inline u64 F(u64 x){return (x^=mask,x^=x<<13,x^=x>>7,x^=x<<17)^mask;}
inline void dfs1(ll x){f[x]=1;for(ll y:G[x]) dfs1(y),f[x]+=F(f[y]);}
inline void dfs2(ll x){for(ll y:G[x]) g[y]=f[y]+F(g[x]-F(f[y])),dfs2(y);}
signed main(){
read(m);fo(1,j,m)
{
read(n);fo(1,i,n) read(fa[i]),fa[i]?G[fa[i]].pb(i),1:rt=i;
dfs1(rt),g[rt]=f[rt],dfs2(rt);ans=0;fo(1,i,n) ans+=g[i],st[j].insert(g[i]),g[i]=f[i]=0,G[i].clear();
// if(!mp.count(ans)) mp[ans]=i;vec.pb(ans);
ll fl=j;for(u64 i:st[j]) fo(1,k,j-1) if(st[k].find(i)!=st[k].end()) ckmn(fl,k);wr(fl),pr;
}
return 0;
}
3.3 圆方树
边仙人掌的 corner case 比较多,可以背一下。
模板圆方树
const ll N=2e4+5,M=1e5+5;
ll n,m,q,u,v,w,vdcc,cnt,dfn[N],low[N],fa[N],a[N],len[N],top[N],id[N],son[N],dep[N],siz[N],rid[N];vector<pii> g[N],G[N];
bool ED;
inline void buildG(ll x,ll y,ll w)
{
++vdcc;ll nw=y,sum=w,val;while(nw!=fa[x]) len[nw]=sum,sum+=a[nw],nw=fa[nw];sum-=a[x];
len[vdcc]=sum,len[x]=0,nw=y;while(nw!=fa[x]) val=min(len[nw],sum-len[nw]),G[vdcc].pb(mk(nw,val)),G[nw].pb(mk(vdcc,val)),nw=fa[nw];
}
inline void tarjan(ll x,ll f)
{
dfn[x]=low[x]=++cnt;
for(auto [y,w]:g[x]) if(y!=f)
{
if(!dfn[y]) fa[y]=x,a[y]=w,tarjan(y,x),ckmn(low[x],low[y]);
else ckmn(low[x],dfn[y]);if(low[y]>dfn[x]) G[x].pb(mk(y,w)),G[y].pb(mk(x,w));
}for(auto [y,w]:g[x]) if(fa[y]!=x&&dfn[y]>dfn[x]) buildG(x,y,w);
}
inline void dfs1(ll x,ll f,ll d){fa[x]=f,siz[x]=1,dep[x]=d;for(auto [y,w]:G[x]) if(y!=f){a[y]=a[x]+w,dfs1(y,x,d+1),siz[x]+=siz[y];if(siz[y]>siz[son[x]]) son[x]=y;}}
inline void dfs2(ll x,ll nt){id[x]=++cnt,rid[cnt]=x,top[x]=nt;if(!son[x])return;dfs2(son[x],nt);for(auto [y,w]:G[x]) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);}
inline ll LCA(ll x,ll y){while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];return dep[x]<dep[y]?x:y;}
inline ll LCA_pre(ll x,ll y){ll las=x;while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?las=top[y],y=fa[top[y]]:(las=top[x],x=fa[top[x]]);return x==y?las:(dep[x]<dep[y]?rid[id[x]+1]:rid[id[y]+1]);}
signed main(){
read(n,m,q);fo(1,i,m) read(u,v,w),g[u].pb(mk(v,w)),g[v].pb(mk(u,w));
vdcc=n,tarjan(1,0);;a[1]=0,cnt=0,dfs1(1,0,1),dfs2(1,1);fo(1,i,q)
{
read(u,v),w=LCA(u,v);
if(w<=n) wr(a[u]+a[v]-2*a[w]),pr;
else
{
ll _u=LCA_pre(u,w),_v=LCA_pre(v,w),ans=a[u]-a[_u]+a[v]-a[_v];
if(len[_u]<len[_v]) swap(_u,_v);ans+=min(len[_u]-len[_v],len[w]+len[_v]-len[_u]),wr(ans),pr;
}
}
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
3.4 同余最短路
同余最短路
const ll N=5e5+5,M=1e5+5;
ll n,l,r,a[N],ans,f[N],_a[N];
bool ED;
signed main(){
n=3,l=0;read(r),--r;fo(1,i,3){read(a[i]);if(!a[i]) --i,--n;}sort(a+1,a+1+n);fo(0,i,a[1]-1) f[i]=INF;f[0]=0;fo(2,i,n) _a[i]=a[i]%a[1];
fo(2,i,n) fo(0,j,__gcd(a[i],a[1])-1) for(ll nw=j,c=0,_nw;c<2;c+=nw==j) _nw=(nw+_a[i]>=a[1]?nw+_a[i]-a[1]:nw+_a[i]),ckmn(f[_nw],f[nw]+a[i]),nw=_nw;
fo(0,i,a[1]-1) ans+=(f[i]<=r)*((r-f[i])/a[1]+1)-(f[i]<l)*((l-1-f[i])/a[1]+1);wr(ans),pr;
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
3.5 环计数
按度数排序,定个向就可以保证每个点出度不超过 \(O(\sqrt n)\)。
三元环计数
const ll N=1e6+5,M=1e5+5;
ll n,m,u,v,deg[N],vis[N],ans;vector<pii> E;vector<ll> g[N];
bool ED;
signed main(){
read(n,m);fo(1,i,m) read(u,v),E.pb(mk(u,v)),deg[u]++,deg[v]++;
for(auto [u,v]:E) (deg[u]>deg[v]||(deg[u]==deg[v]&&u>v)?swap(u,v),1:1),g[u].pb(v);
fo(1,i,n)
{
for(ll j:g[i]) vis[j]=i;
for(ll j:g[i]) for(ll k:g[j]) ans+=vis[k]==i;
}wr(ans),pr;
cerr << "Time: " << (double)clock()/CLOCKS_PER_SEC << "s\n";
cerr << "Memory: " << abs(&ST - &ED) / 1024.0 / 1024.0 << " MB\n";
return 0;
}
4. 数学
4.1 写了的部分
可能,大部分有用的,都在这了,再多了我也不会了。
4.2 exLuacs
5. 字符串
来点字符串哈希封装,发现之前好多次一直不会写简单的字符串哈希。
#include <bits/stdc++.h>
using namespace std;
using u64 = uint64_t;
using H = pair<u64, u64>;
struct SH {
static constexpr u64 M[2] = {1000000007ULL, 1000000009ULL};
static constexpr u64 B[2] = {131, 137};
int n = 0;
string s;
vector<u64> h[2], r[2], p[2];
SH() = default;
SH(const string& t) { init(t); }
void init(const string& t) {
s = t; n = s.size();
for (int k = 0; k < 2; k++) h[k].assign(n + 1, 0), r[k].assign(n + 1, 0), p[k].assign(n + 1, 1);
for (int i = 0; i < n; i++) {
u64 v = s[i] + 1, w = s[n - 1 - i] + 1;
for (int k = 0; k < 2; k++) {
h[k][i+1] = (h[k][i] * B[k] + v) % M[k];
r[k][i+1] = (r[k][i] * B[k] + w) % M[k];
p[k][i+1] = p[k][i] * B[k] % M[k];
}
}
}
H get(int l, int r) const {
return {(h[0][r] + M[0] - h[0][l] * p[0][r-l] % M[0]) % M[0],
(h[1][r] + M[1] - h[1][l] * p[1][r-l] % M[1]) % M[1]};
}
H rev(int l, int r) const {
int L = n - r, R = n - l;
return {(r[0][R] + M[0] - r[0][L] * p[0][R-L] % M[0]) % M[0],
(r[1][R] + M[1] - r[1][L] * p[1][R-L] % M[1]) % M[1]};
}
bool pal(int l, int r) const { return get(l, r) == rev(l, r); }
int lcp(int i, int j) const { return lcp(*this, i, *this, j); }
static int lcp(const SH& x, int i, const SH& y, int j) {
int lo = 0, hi = min(x.n - i, y.n - j);
while (lo < hi) { int m = (lo + hi + 1) >> 1; x.get(i, i+m) == y.get(j, j+m) ? lo = m : hi = m - 1; }
return lo;
}
int cmp(int a, int b, int c, int d) const { return cmp(*this, a, b, *this, c, d); }
static int cmp(const SH& x, int a, int b, const SH& y, int c, int d) {
int m = min(b - a, d - c), t = lcp(x, a, y, c);
if (t >= m) return (b - a == d - c) ? 0 : (b - a < d - c ? -1 : 1);
return x.s[a + t] < y.s[c + t] ? -1 : 1;
}
};

浙公网安备 33010602011771号