火车头:
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
高精度:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int a[maxn],b[maxn],res[maxn];
string add(string s1,string s2){
int n=s1.length(),m=s2.length();
for(int i=0;i<n;i++)a[i]=s1[n-1-i]-'0';
for(int i=0;i<m;i++)b[i]=s2[m-1-i]-'0';
int len=max(n,m)+1;
for(int i=n;i<len;i++)a[i]=0;
for(int i=m;i<len;i++)b[i]=0;
for(int i=0;i<len;i++)res[i]=0;
for(int i=0;i<len;i++){
res[i]+=a[i]+b[i];
if(res[i]>=10){
res[i+1]+=res[i]/10;
res[i]%=10;
}
}
int i=len-1;
while(res[i]==0&&i>0)i--;
string s="";
for(;i>=0;i--)s+=(char)(res[i]+'0');
return s;
}
string sub(string s1,string s2){
int n=s1.length(),m=s2.length();
for(int i=0;i<n;i++)a[i]=s1[n-1-i]-'0';
for(int i=0;i<m;i++)b[i]=s2[m-1-i]-'0';
int len=max(n,m);
for(int i=n;i<len;i++)a[i]=0;
for(int i=m;i<len;i++)b[i]=0;
for(int i=0;i<len;i++)res[i]=0;
for(int i=0;i<len;i++){
res[i]+=a[i]-b[i];
if(res[i]<0){
res[i+1] --;
res[i] += 10;
}
}
int i=len-1;
while(res[i]==0&&i>0)i--;
string s="";
for(;i>=0;i--)s+=(char)(res[i]+'0');
return s;
}
bool cmp(string s1,string s2){
int n=s1.length(),m=s2.length();
int i;
for(i=0;i<n-1&&s1[i]=='0';i++);
s1=s1.substr(i);
for(i=0;i<m-1&&s2[i]=='0';i++);
s2=s2.substr(i);
if(s1.length()!=s2.length())return s1.length()<s2.length();
return s1<s2;
}
string Add(string s1,string s2){
if(s1[0]=='-'&&s2[0]=='-'){
return "-"+add(s1.substr(1),s2.substr(1));
}
else if(s1[0]=='-'){
s1=s1.substr(1);
if(cmp(s1,s2)==true){
return sub(s2,s1);
}else{
return "-"+sub(s1,s2);
}
}
else if(s2[0]=='-'){
s2=s2.substr(1);
if(cmp(s1,s2)){
return "-"+sub(s2,s1);
}else{
return sub(s1,s2);
}
}
else{
return add(s1,s2);
}
}
string multi(string s1,string s2){
int n=s1.length(), m=s2.length();
for(int i=0;i<n;i++)a[i]=s1[n-1-i]-'0';
for(int i=0;i<m;i++)b[i]=s2[m-1-i]-'0';
int len=n+m;
for(int i=n;i<len;i++)a[i]=0;
for(int i=m;i<len;i++)b[i]=0;
for(int i=0;i<len;i++)res[i]=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
res[i+j]+=a[i]*b[j];
for(int i=0;i<len;i++){
res[i+1]+=res[i]/10;
res[i]%=10;
}
int i=len-1;
while(res[i]==0&&i>0)i--;
string s="";
for(;i>=0;i--)s+=(char)(res[i]+'0');
return s;
}
string divide(string s1,string s2){
string s="",t="";
int n=s1.length(),m=s2.length();
bool flag=false;
for(int i=0;i<n;i++){
s+=s1[i];
int num=0;
while(cmp(s,s2)==false){
num++;
s=sub(s,s2);
}
if(num>0){
flag=true;
char c=(char)(num+'0');
t+=c;
}
else if(flag){
t+='0';
}
}
if(t.length()==0)t="0";
return t;
}
int main(){
string s1,s2;
cin>>s1>>s2;
cout<<"Add:"+s1+'+'+s2+'='+Add(s1,s2)+'\n';
cout<<"Sub:"+s1+'-'+s2+'='+Add(s1,'-'+s2)+'\n';
cout<<"Mul:"+s1+'*'+s2+'='+multi(s1,s2)+'\n';
cout<<"Div:"+s1+'/'+s2+'='+divide(s1,s2)+'\n';
}
fio快读快输
class fast_iostream{
private:
const int MAXBF = 1 << 20; FILE *inf, *ouf;
char *inbuf, *inst, *ined;
char *oubuf, *oust, *oued;
inline void _flush(){fwrite(oubuf, 1, oued - oust, ouf);}
inline char _getchar(){
if(inst == ined) inst = inbuf, ined = inbuf + fread(inbuf, 1, MAXBF, inf);
return inst == ined ? EOF : *inst++;
}
inline void _putchar(char c){
if(oued == oust + MAXBF) _flush(), oued = oubuf;
*oued++ = c;
}
public:
fast_iostream(FILE *_inf = stdin, FILE * _ouf = stdout)
:inbuf(new char[MAXBF]), inf(_inf), inst(inbuf), ined(inbuf),
oubuf(new char[MAXBF]), ouf(_ouf), oust(oubuf), oued(oubuf){}
~fast_iostream(){_flush(); delete inbuf; delete oubuf;}
template <typename Int>
fast_iostream& operator >> (Int &n){
static char c;
while((c = _getchar()) < '0' || c > '9');n = c - '0';
while((c = _getchar()) >='0' && c <='9') n = n * 10 + c - '0';
return *this;
}
template <typename Int>
fast_iostream& operator << (Int n){
if(n < 0) _putchar('-'), n = -n; static char S[20]; int t = 0;
do{S[t++] = '0' + n % 10, n /= 10;} while(n);
for(int i = 0;i < t;++i) _putchar(S[t - i - 1]);
return *this;
}
fast_iostream& operator << (char c){_putchar(c); return *this;}
fast_iostream& operator << (const char *s){
for(int i = 0;s[i];++i) _putchar(s[i]); return *this;
}
}fio;
普通快读快写
inline long long read()
{
long long x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline void write(long long x)
{
if(x==0)
{
putchar('0');
return;
}
char F[200];
long long tmp=x>0?x:-x;
if(x<0) putchar('-');
long long cnt=0;
while(tmp>0)
{
F[cnt++]=tmp%10+'0';
tmp/=10;
}
while(cnt>0)putchar(F[--cnt]);
}
组合数
int qzj[20000001],inv[20000001];
long long poww(long long a,long long b)
{
long long re=1;
while(b)
{
if(b&1)
{
re*=a;
re%=mod;
}
a*=a;
a%=mod;
b>>=1;
}
return re;
}
int C(int a,int b)
{
if(b>a) return 0;
return 1ll*qzj[a]*inv[a-b]%mod*inv[b]%mod;
}
signed main()
{
qzj[0]=1;
for(int i=1;i<=20000000;i++)
{
qzj[i]=1ll*qzj[i-1]*i%mod;
}
inv[20000000]=poww(qzj[20000000],mod-2);
for(int i=20000000-1;i>=0;i--)
{
inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
}
模板字典树:
#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<string>
using namespace std;
struct ac
{
int nxt[27],num;
}ac[1000001];
int n,m,p;
void add(string a)
{
int P=0;
for(int i=0;i<a.size();i++)
{
int t=a[i]-'a';
if(!ac[P].nxt[t])
{
ac[P].nxt[t]=++p;
}
P=ac[P].nxt[t];
}
ac[P].num++;
return;
}
bool serch(string a)
{
int P=0;
for(int i=0;i<a.size();i++)
{
int t=a[i]-'a';
if(!ac[P].nxt[t])
{
return false;
}
P=ac[P].nxt[t];
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
string a;
cin>>a;
add(a);
}
for(int i=1;i<=m;i++)
{
string a;
cin>>a;
printf(serch(a) ? "FIND\n" : "UNFIND\n");
}
}
分块
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
int n,m,st[250000],ed[250000],sum[250000],a[500001],pos[500001],len,w,ww,ans,opt,l,r,x,tag[250001];
void make()
{
len=sqrt(n);
for(int i=1;i*i<=n;i++)
{
st[i]=(i-1)*len+1;
ed[i]=i*len;
for(int z=st[i];z<=ed[i];z++)
{
sum[i]+=a[z];
pos[z]=i;
}
}
if(len*len!=n)
{
st[len+1]=len*len+1;
ed[len+1]=n;
for(int z=st[len+1];z<=ed[len+1];z++)
{
sum[len+1]+=a[z];
pos[z]=len+1;
}
len++;
}
}
void add(int l,int r,int x)
{
w=pos[l];
ww=pos[r];
if(ww==w)
{
for(int i=l;i<=r;i++)
{
a[i]+=x;
sum[w]+=x;
}
}
else
{
for(int i=l;i<st[w+1];i++)
{
a[i]+=x;
sum[w]+=x;
}
for(int i=w+1;i<ww;i++)
{
sum[i]+=(ed[i]-st[i]+1)*x;
tag[i]+=x;
}
for(int i=ed[ww-1]+1;i<=r;i++)
{
a[i]+=x;
sum[ww]+=x;
}
}
}
int get(int l,int r)
{
int ans;
w=pos[l];
ww=pos[r];
if(ww==w)
{
ans=0;
for(int i=l;i<=r;i++)
{
ans+=a[i]+tag[w];
}
return ans;
}
else
{
ans=0;
for(int i=l;i<st[w+1];i++)
{
ans+=a[i]+tag[w];
}
for(int i=w+1;i<ww;i++)
{
ans+=sum[i];
}
for(int i=ed[ww-1]+1;i<=r;i++)
{
ans+=a[i]+tag[ww];
}
return ans;
}
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
make();
for(int i=1,opt,l,r,v;i<=m;i++)
{
scanf("%lld%lld%lld",&opt,&l,&r);
if(opt==1)
{
scanf("%lld",&v);
add(l,r,v);
}
else
{
cout<<get(l,r)<<endl;
}
}
}
懒标记线段树
#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,sum[4000004],tag[4000004],a,p,x,y,v;
void addtag(long long o,long long l,long long r,long long v)
{
tag[o]+=v;
sum[o]+=(r-l+1)*v;
}
void downtag(long long o,long long l,long long r)
{
if(tag[o]==0) return;
long long mid=r+l>>1;
addtag((o<<1),l,mid,tag[o]);
addtag((o<<1)+1,mid+1,r,tag[o]);
tag[o]=0;
}
void uptag(long long o)
{
sum[o]=sum[o<<1]+sum[(o<<1)+1];
}
void add(long long o,long long l,long long r,long long x,long long y,long long v)
{
if(l>y || r<x)
{
return;
}
if(x<=l && r<=y)
{
addtag(o,l,r,v);
return;
}
long long mid=r+l>>1;
downtag(o,l,r);
add((o<<1),l,mid,x,y,v);
add((o<<1)+1,mid+1,r,x,y,v);
uptag(o);
}
long long get(long long o,long long l,long long r,long long x,long long y)
{
if(l>y || r<x)
{
return 0;
}
if(x<=l && r<=y)
{
return sum[o];
}
long long mid=l+r>>1;
downtag(o,l,r);
return get(o<<1,l,mid,x,y)+get((o<<1)+1,mid+1,r,x,y);
}
int main()
{
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++)
{
scanf("%lld",&a);
add(1,1,n,i,i,a);
}
for(long long i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&p,&x,&y);
if(p&1)
{
scanf("%lld",&v);
add(1,1,n,x,y,v);
}
else
{
printf("%lld\n",get(1,1,n,x,y));
}
}
}
线段树
#include<iostream>
#include<cstdio>
#define INF 0x7f7f7f
using namespace std;
int n,m,mi[400004],a,p,x,y;
void add(int o,int l,int r,int x,int y)
{
if(l==r)
{
mi[o]=y;
return;
}
int mid=r+l>>1;
if(x<=mid) add((o<<1),l,mid,x,y);
else add((o<<1)+1,mid+1,r,x,y);
mi[o]=min(mi[(o<<1)],mi[(o<<1)+1]);
}
int get(int o,int l,int r,int x,int y)
{
if(x>r || y<l) return INF;
if(x<=l&&y>=r) return mi[o];
int mid=l+r>>1;
return min(get(o<<1,l,mid,x,y),get((o<<1)+1,mid+1,r,x,y));
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
add(1,1,n,i,a);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&p,&x,&y);
if(p&1) printf("%d ",get(1,1,n,x,y));
else add(1,1,n,x,y);
}
}
权值线段树:
#include<iostream>
#include<cstdio>
#define INF 0x7f7f7f
using namespace std;
long long n,m,a,p,x,y,ma=-2147483647,mi=2147483647,area=1ll,len=1ll/*此处开1ll会与其他指针重合*/;
struct polo
{
long long l,r,w;
}sum[4000003];
void add(long long &o,long long l,long long r,long long x,long long v) //插入
{
if(!o) o=++len; //新点
if(l==r)
{
sum[o].w+=v;
return;
}
long long mid=r+l>>1ll;
if(x<=mid) add((sum[o].l),l,mid,x,v);
else add(sum[o].r,mid+1ll,r,x,v);
sum[o].w=sum[(sum[o].l)].w+sum[sum[o].r].w;
}
long long get(long long o,long long l,long long r,long long k) //k出现的次数
{
if(l==r) return sum[o].w;
long long mid=l+r>>1ll;
return (k<=mid ? get(sum[o].l,l,mid,k) : get(sum[o].r,mid+1ll,r,k));
}
long long find(long long o,long long l,long long r,long long x,long long y) //x-y数的个数
{
if(!o) return 0;
if(x>r || y<l) return 0;
if(x<=l&&y>=r) return sum[o].w;
long long mid=l+r>>1ll;
return find(sum[o].l,l,mid,x,y)+find(sum[o].r,mid+1ll,r,x,y);
}
long long fsmall(long long o,long long l,long long r,long long k) //求第k小的数
{
if(l==r) return l;
long long mid=l+r>>1ll;
if(k<=sum[(sum[o].l)].w) return fsmall((sum[o].l),l,mid,k);
else return fsmall(sum[o].r,mid+1ll,r,k-sum[(sum[o].l)].w);
}
long long fbig(long long o,long long l,long long r,long long k) //求第k大的数
{
if(l==r) return l;
long long mid=l+r>>1ll;
if(k<=sum[sum[o].r].w) return fbig(sum[o].r,mid+1ll,r,k);
else return fbig((sum[o].l),l,mid,k-sum[sum[o].r].w);
}
long long lowerbound(long long l,long long r,long long k) //前驱
{
return fsmall(1ll,l,r,find(1ll,l,r,-10000001,k-1ll));
}
long long upperbound(long long l,long long r,long long k) //后继
{
return fsmall(1ll,l,r,find(1ll,l,r,-10000001,k)+1ll);
}
int main()
{
scanf("%lld",&n);
for(long long i=1ll,opt;i<=n;i++)
{
scanf("%lld%lld",&opt,&a);
if(opt==1ll)
{
add(area,-10000001,10000001,a,1ll);
}
if(opt==2)
{
add(area,-10000001,10000001,a,-1ll);
}
if(opt==3)
{
printf("%lld\n",find(1ll,-10000001,10000001,1ll,a-1ll)+1ll);
}
if(opt==4)
{
printf("%lld\n",fsmall(area,-10000001,10000001,a));
}
if(opt==5)
{
printf("%lld\n",lowerbound(-10000001,10000001,a));
}
if(opt==6)
{
printf("%lld\n",upperbound(-10000001,10000001,a));
}
}
}
可持久化权值线段树
#include<iostream>
#include<cstdio>
#define INF 0x7f7f7f
using namespace std;
int n,m,a,ma,root[200001],mi=2147483647,area=1,len=1/*此处开1会与其他指针重合*/;
struct polo
{
int l,r,w;
}sum[8000001];
void add(int &o,int p,int l,int r,int x,int v) //插入
{
o=++len;
sum[o]=sum[p]; //新点
if(l==r)
{
sum[o].w+=v;
return;
}
int mid=r+l>>1;
if(x<=mid) add((sum[o].l),(sum[p].l),l,mid,x,v);
else add(sum[o].r,sum[p].r,mid+1,r,x,v);
sum[o].w=sum[(sum[o].l)].w+sum[sum[o].r].w;
}
int get(int o,int l,int r,int k) //k出现的次数
{
if(l==r) return sum[o].w;
int mid=l+r>>1;
return (k<=mid ? get(sum[o].l,l,mid,k) : get(sum[o].r,mid+1,r,k));
}
int fsmall(int o,int p,int l,int r,int k) //求第k小的数
{
if(l==r) return l;
int mid=l+r>>1,fuck=sum[sum[o].l].w-sum[sum[p].l].w;
if(k<=fuck) return fsmall((sum[o].l),(sum[p].l),l,mid,k);
else return fsmall(sum[o].r,sum[p].r,mid+1,r,k-fuck);
}
int fsum(int o,int p,int l,int r,int f,int k) //区间值[f,k]的数的个数
{
if(f<=l&&r<=k)
{
return sum[o].w-sum[p].w;
}
if(l>k||r<f)
{
return 0;
}
int mid=r+l>>1;
return fsum(sum[o].l,sum[p].l,l,mid,f,k)+fsum(sum[o].r,sum[p].r,mid+1,r,f,k);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
add(root[i],root[i-1],-1000000001,1000000001,a,1);
}
for(int i=1,l,r;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&a);
printf("%d\n",fsmall(root[r],root[l-1],-1000000001,1000000001,a));
}
}
dij最短路
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int n,m,a[10001],u,v,w;
struct edge
{
int u,v,w;
};
struct point
{
int id,d;
bool operator < (point a) const
{
return d>a.d;
}
};
vector <edge> g[10001];
bool vis[10001];
priority_queue<point> q;
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
g[u].push_back((edge){u,v,w});
}
memset(a,0x7f,sizeof(a));
a[1]=0;
q.push((point){1,0});
while(q.empty()==false)
{
int u=q.top().id;
q.pop();
vis[u]=true;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v;
int w=g[u][i].w;
if(vis[v]) continue;
if(a[u]+w<a[v])
{
a[v]=a[u]+w;
q.push((point){v,a[v]});
}
}
}
cout<<a[n];
}
最近公共祖先
#include<iostream>
#include<cstdio>
#include<vector>
#define log 20
using namespace std;
int n,m,k,father[500001][21],deep[500001]; //father[i][j] 表示点i的第2^j个祖先,转移方程:father[i][j]=father[father[i][j-1]][j-1]
vector <int> g[500001];
void getfather(int u,int fa)
{
father[u][0]=fa; //初始化
for(int i=1;i<=log;i++)
{
father[u][i]=father[father[u][i-1]][i-1]; //转移
}
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa) continue;
getfather(v,u); //向下搜索
}
}
void getdeep(int u,int fa)
{
deep[u]=deep[fa]+1; //统计深度
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa) continue;
getdeep(v,u);
}
}
int getlca(int u,int v)
{
if(deep[u]>deep[v]) swap(u,v); //保证v更深
int mul=deep[v]-deep[u],w=0;
while(mul)
{
if(mul&1) v=father[v][w]; //向上跳
mul>>=1;
w++;
}
if(u==v) return u;
for(int i=log;i>=0;i--)
{
if(father[u][i]!=father[v][i]) //点不同,则不再一条链上
{
u=father[u][i]; //向上跳
v=father[v][i];
}
}
return father[u][0];
}
int main()
{
scanf("%d",&n);
for(int i=1,u,v;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
getfather(1,0); //根为1节点
getdeep(1,0);
scanf("%d",&m);
for(int i=1,u,v;i<=m;i++)
{
scanf("%d%d",&u,&v);
printf("%d\n",getlca(u,v));
}
}
重链剖分
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,q,mod,rt,w[1000001],sum[8000001],tag[8000001];
vector<int> g[1000001];
void addtag(int o,int l,int r,int v)
{
tag[o]+=v%mod;
tag[o]%=mod;
sum[o]+=(r-l+1)%mod*v%mod;
sum[o]%=mod;
}
void downtag(int o,int l,int r)
{
if(tag[o]==0) return;
int mid=r+l>>1;
addtag((o<<1),l,mid,tag[o]);
addtag((o<<1)+1,mid+1,r,tag[o]);
tag[o]=0;
}
void uptag(int o)
{
sum[o]=sum[o<<1]+sum[(o<<1)+1];
sum[o]%=mod;
}
void add(int o,int l,int r,int x,int y,int v)
{
if(l>y || r<x)
{
return;
}
if(x<=l && r<=y)
{
addtag(o,l,r,v);
return;
}
int mid=r+l>>1;
downtag(o,l,r);
add((o<<1),l,mid,x,y,v);
add((o<<1)+1,mid+1,r,x,y,v);
uptag(o);
}
int get(int o,int l,int r,int x,int y)
{
if(l>y || r<x)
{
return 0;
}
if(x<=l && r<=y)
{
return sum[o]%mod;
}
int mid=l+r>>1;
downtag(o,l,r);
return (get(o<<1,l,mid,x,y)+get((o<<1)+1,mid+1,r,x,y))%mod;
}
int fat[100001],siz[100001],dep[100001],hson[100001],top[100001],cnt,dfn[100001],dis[100001];
void getdfsh(int u,int fa) //获取:父节点,深度,子树大小,重儿子
{
fat[u]=fa;
dep[u]=dep[fa]+1;
int lll=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa) continue;
getdfsh(v,u);
if(siz[v]>lll)
{
hson[u]=v;
lll=siz[v];
}
siz[u]+=siz[v];
}
siz[u]++;
}
void gettd(int u,int fa) //获取:链顶,dfs序
{
dfn[u] = ++cnt;
dis[u] = cnt;
if(hson[fat[u]]==u)
{
top[u]=top[fa];
}
else
{
top[u]=u;
}
if(hson[u]!=0) gettd(hson[u],u); //优先重子
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa||v==hson[u]) continue;
gettd(v,u);
}
}
int addlsum(int st,int ed,int v) //一条链的和
{
v%=mod;
if(dfn[st]<dfn[ed]) swap(st,ed);
int u=st,re=0;
while(1)
{
if(dfn[top[u]]<=dfn[ed])
{
add(1,1,n,dfn[ed],dfn[u],v);
break;
}
add(1,1,n,dfn[top[u]],dfn[u],v);
u=fat[top[u]];
}
return re;
}
int getlsum(int st,int ed) //一条链的和
{
if(dfn[st]<dfn[ed]) swap(st,ed);
int u=st,re=0;
while(1)
{
if(dfn[top[u]]<=dfn[ed])
{
re+=get(1,1,n,dfn[ed],dfn[u])%mod;
re%=mod;
break;
}
re+=get(1,1,n,dfn[top[u]],dfn[u])%mod;
re%=mod;
u=fat[top[u]];
}
return re%mod;
}
void getdis(int u, int fa) {
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if (v == fa) continue;
getdis(v, u);
dis[u] = max(dis[u], dis[v]);
}
}
int father[500001][21];
void getfather(int u,int fa)
{
father[u][0]=fa; //初始化
for(int i=1;i<=20;i++)
{
father[u][i]=father[father[u][i-1]][i-1]; //转移
}
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa) continue;
getfather(v,u); //向下搜索
}
}
//void getdeep(int u,int fa)
//{
// dep[u]=dep[fa]+1; //统计深度
// for(int i=0;i<g[u].size();i++)
// {
// int v=g[u][i];
// if(v==fa) continue;
// getdeep(v,u);
// }
//}
int getlca(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v); //保证v更深
int mul=dep[v]-dep[u],w=0;
while(mul)
{
if(mul&1) v=father[v][w]; //向上跳
mul>>=1;
w++;
}
if(u==v) return u;
for(int i=20;i>=0;i--)
{
if(father[u][i]!=father[v][i]) //点不同,则不再一条链上
{
u=father[u][i]; //向上跳
v=father[v][i];
}
}
return father[u][0];
}
signed main()
{
scanf("%lld%lld%lld%lld",&n,&q,&rt,&mod);
for(int i=1;i<=n;i++)
{
scanf("%lld",&w[i]);
}
for(int i=1,u,v;i<n;i++)
{
scanf("%lld%lld",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
getdfsh(rt,0);
gettd(rt,0);
getdis(rt,0);
getfather(rt,0);
for(int i=1;i<=n;i++)
{
add(1,1,n,dfn[i],dfn[i],w[i]);
}
for(int i=1,opt,u,v,w;i<=q;i++)
{
scanf("%lld%lld",&opt,&u);
if(opt==2)
{
scanf("%lld",&v);
int lca=getlca(u,v);
printf("%lld\n",((getlsum(u,lca)+getlsum(v,lca)-get(1,1,n,dfn[lca],dfn[lca]))%mod+mod)%mod);
}
if(opt==1)
{
scanf("%lld",&v);
int lca=getlca(u,v);
scanf("%lld",&w);
w%=mod;
addlsum(u,lca,w);
addlsum(v,lca,w);
add(1,1,n,dfn[lca],dfn[lca],-w);
}
if(opt==4)
{
//cout<<dfn[u]<<' '<<dis[u]<<endl;
printf("%lld\n",get(1,1,n,dfn[u],dis[u])%mod);
}
if(opt==3)
{
scanf("%lld",&w);
w%=mod;
add(1,1,n,dfn[u],dis[u],w);
}
}
}
笛卡尔树
#include<iostream>
#include<cstdio>
using namespace std;
int n,a[1000001],lson[1000001],rson[1000001],tr[1000001],st[1000001],len,pt,root;
void bd_t()
{
pt=len;
for(int i=1;i<=n;i++)
{
while(pt&&a[st[pt]]>a[i]) pt--; //维护单调栈
if(pt) rson[st[pt]]=i; //如果有父亲,设到父亲的右儿子
if(pt<len) lson[i]=st[pt+1]; //如果父亲有原右儿子,放到左儿子
st[++pt]=i; //入栈
len=pt;
}
root=st[1];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
bd_t();
}
KMP
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[10000001],b[10000001];
int kmp[10000001],fail,strlena,strlenb,ans;
int main()
{
scanf(" %s %s",a+1,b+1);
strlena=strlen(a+1);
strlenb=strlen(b+1);
for(int i=2;i<=strlenb;i++)
{
while(fail>0 && b[i]!=b[fail+1]) fail=kmp[fail];
if(b[i]==b[fail+1]) fail++;
kmp[i]=fail; //找出失配指针
}
fail=0; //初始化
for(int i=1;i<=strlena;i++)
{
while(fail>0 && a[i]!=b[fail+1]) fail=kmp[fail]; //跳fail指针
if(a[i]==b[fail+1]) fail++;
if(fail==strlenb) //整串匹配
{
ans++;
fail=kmp[fail]; //向回跳
}
}
printf("%d",ans);
}
字符串哈希
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
string a,b;
unsigned long long dl=1,d=998244353,ha,hb;
long long la,lb,ans;
int main()
{
cin>>a>>b;
la=a.size();
lb=b.size();
for(int i=0;i<la;i++)
{
ha*=d;
hb*=d;
ha+=a[i];
hb+=b[i];
dl*=d;
}
if(ha==hb) ans++,las=la-1;
for(int i=la;i<lb;i++)
{
hb*=d;
hb=hb-b[i-la]*dl+b[i];
if(ha==hb)
{
ans++;
}
}
printf("%lld",ans);
}
AC自动机
#include<iostream>
#include<string>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,p,ans,jumper[1000001];
struct ac
{
int nxt[27],fail,num,up;
}ac[1000001];
string s[151],t;
void add(string a,int kda)
{
int P=0;
for(int i=0;i<a.size();i++)
{
int t=a[i]-'a';
if(!ac[P].nxt[t])
{
ac[P].nxt[t]=++p;
}
P=ac[P].nxt[t];
}
jumper[kda]=P;
ac[P].num++;
return;
}
void getfail()
{
queue <int> q;
for(int u=0;u<26;u++) //预处理根
{
if(ac[0].nxt[u]) //有这条边
{
ac[ac[0].nxt[u]].fail=0; //fail指针设到根
q.push(ac[0].nxt[u]);
}
}
while(!q.empty()) //bfs
{
int u=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(ac[u].nxt[i]) //儿子存在
{
ac[ac[u].nxt[i]].fail=ac[ac[u].fail].nxt[i]; //将儿子的fail指针指向自己fail指针的同一个儿子
q.push(ac[u].nxt[i]); //压入队列
}
else
{
ac[u].nxt[i]=ac[ac[u].fail].nxt[i];//跳到fail指针
}
}
}
}
void work(string t)
{
int AC=0,re=0,jump;
for(int i=0;i<t.size();i++)
{
AC=ac[AC].nxt[t[i]-'a'];
jump=AC;
while(jump>0)
{
ac[jump].up++/*=ac[jump].num*/; //试试就逝世
jump=ac[jump].fail;
}
}
}
int serch(string a)
{
int P=0;
for(int i=0;i<a.size();i++)
{
// cout<<P<<' ';
int t=a[i]-'a';
if(!ac[P].nxt[t])
{
return -1;
}
int jump=ac[P].nxt[t];
while(jump>0&&ac[jump].num)
{
ans+=ac[jump].num;
ac[jump].num=-1;
jump=ac[jump].fail;
}
P=ac[P].nxt[t];
}
// cout<<P<<':'<<ac[P].up<<'\n';
return ac[P].up;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s[i];
add(s[i],i);
}
getfail();
cin>>t;
work(t);
}
manacher 算法
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
char b[50000001],a[50000001];
int len,ma,w,ans,mlc[50000001];
int main()
{
cin>>a;
b[0]='$';
len=strlen(a);
for(int i=0;i<len;i++)
{
b[i*2+1]='#';
b[i*2+2]=a[i];
}
b[len*2+1]='#';
b[len*2+2]='\0';
// cout<<b;
len=strlen(b);
for(int i=1;i<len;i++)
{
if(i<ma)
{
mlc[i]=min(mlc[2*w-i],ma-i);
}
else
{
mlc[i]=1;
}
while(b[i+mlc[i]]==b[i-mlc[i]])
{
mlc[i]++;
}
if(mlc[i]+i>ma)
{
ma=mlc[i]+i;
w=i;
}
ans=max(ans,mlc[i]-1);
}
printf("%d",ans);
}
欧拉筛
void ola()
{
for(int i=2;i<=a;i++)
{
if(!vis[i]) prm[++len]=i;
for(int z=1;z<=len&&i*prm[z]<=a;z++)
{
vis[i*prm[z]]=true;
if(i%prm[z]==0) break;
}
}
}
埃氏筛
void work()
{
for(long long i=2;i*i<=n;i++)
{
if(!vis[i])
{
for(long long z=i*i;z<=n;z+=i)
{
vis[z]=true;
}
}
}
}