ST表
for(int i=1;i<=N;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);
}
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
int len=log2(y-x+1);
int ans=max(f[x][len],f[y-(1<<len)+1][len]);
printf("%d\n",ans);
}
割点
void tarjan(long long u,long long root){
st[++top]=u;
long long son=0;
dfn[u]=low[u]=++visn;
for(long long i=head[u];i;i=edge[i].next){
long long to=edge[i].to;
if(!dfn[to]){
son++;
tarjan(to,u);
low[u]=min(low[u],low[to]);
if((u==root&&son>1)||(root!=u&&low[to]>=dfn[u]))cut[u]=1;
}
low[u]=min(low[u],dfn[to]);
}
}
2-SAT
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 4000007;
struct node{
int to,next;
}edge[maxn*2];
int cnt,head[maxn];
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
int dfn[maxn],low[maxn],n,m,st[maxn],instack[maxn],visn,tot,top,co[maxn];
void tarjan(int u){
dfn[u]=low[u]=++visn;
st[++top]=u;
instack[u]=1;
for(int i=head[u];i;i=edge[i].next){
int to=edge[i].to;
if(!dfn[to]){
tarjan(to);
low[u]=min(low[u],low[to]);
}
else if(instack[to])low[u]=min(low[u],dfn[to]);
}
if(dfn[u]==low[u]){
tot++;int t;
do{
t=st[top--];
co[t]=tot;
instack[t]=0;
}while(t!=u);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,a,b;
scanf("%d%d%d%d",&a,&x,&b,&y);
if(x==1&&y==1){add(a,b+n),add(b,a+n);}
if(x==1&&y==0){add(a,b),add(b+n,a+n);}
if(x==0&&y==1){add(a+n,b+n),add(b,a);}
if(x==0&&y==0){add(a+n,b),add(b+n,a);}
}
for(int i=1;i<=2*n;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;i++){
if(co[i]==co[i+n]){
puts("IMPOSSIBLE");
return 0;
}
}
puts("POSSIBLE");
for(int i=1;i<=n;i++){
if(co[i]>co[i+n])printf("1 ");
else printf("0 ");
}
return 0;
}
裴蜀定理
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int n,ans;
int main(){
scanf("%d%d",&n,&ans);
for(int i=2;i<=n;i++){
int x;scanf("%d",&x);
ans=gcd(ans,abs(x));
}
cout<<ans;
}
线性递推逆元
inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=((p-p/i)*inv[p%i])%p;
}
拓展欧几里得
void exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;
y=0;
return a;
}int t=exgcd(b,a%b,x,y);
int xx=x;
x=y;
y=xx-(a/b)*y;
}
NIM游戏
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int T,n;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int SG=0;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);SG^=x;
}
if(!SG)puts("No");
else puts("Yes");
}
代码是可以无限取的SG(x)=x
对于只能取m个的,SG(x)=x%(m+1);
因为对于每一个(k+1)*(m+1),我们总可以使他变成k*(m+1)
当小于m+1时,就是无限制取法
对于只能取f={a1,a2,a3....an}个的
我们使用集合的mex操作
SG(x)=mex(x-f{a1,a2,a3...an});
部分建模
1.硬币翻转 ,每一个位置为i的朝上硬币,他的SG值就为i
2.阶梯,我们只考虑奇数级阶梯,因为偶数级阶梯,我们可以通过两次移动消除他的影响
对于奇数级阶梯进行nim即可,SG值为石子数
3.ANTI-NIM游戏 当可决策集合为空时,为必败态。
先手必胜当且仅当:
所有堆的石子数都为1且游戏的SG值为0
有些堆的石子数大于1且游戏的SG值不为0
4.使用mex函数打表找规律吧
}
二叉堆
switch(a){
case 1:q:cin>>b;q.push(0-b);break;
case 2:cout<<0-q.top()<<endl;break;
case 3:q.pop();break;
}
缩点
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 10005;
struct node{int to,next,w;}edge[maxn*10];
int head[maxn],n,m,cnt=1,instack[maxn],dfn[maxn],low[maxn];
int stack[maxn],rd[maxn],num[maxn],sum[maxn],tot,co[maxn],top,visn=1,root[maxn];
long long int dp[maxn];
pair<int,int> g[10*maxn];
queue < int > q;
void add(int from,int to){
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt++;
}
void work(){
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>num[i];
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
add(x,y);
g[i].first=x;
g[i].second=y;
}
}
long long int tpsort(){
for(int i=1;i<=n;i++){
if(rd[i]==0&&co[i]==i)
q.push(co[i]);
dp[co[i]]=sum[co[i]];
}
while(!q.empty()){
int f1=q.front();
q.pop();
for(int i=head[f1];i!=-1;i=edge[i].next){
int to=edge[i].to;
int w=edge[i].w;
dp[to]=max(dp[f1]+sum[co[to]],dp[to]);
if(--rd[to])q.push(to);
}
}
long long ans=-1;
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
return ans;
}
void tarjan(int u){
stack[++top]=u;instack[u]=1;
dfn[u]=low[u]=visn++;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[v],low[u]);
}
else if(instack[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int t;
do{
t=stack[top--];
sum[u]+=num[t];
instack[t]=0;
co[t]=u;
}while(t!=u);
}
}
int main(){
work();
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
for(int i=1;i<=cnt;i++)edge[i].to=edge[i].next=0;
cnt=1;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
int f1=g[i].first;
int f2=g[i].second;
if(co[f1]!=co[f2])
add(co[f1],co[f2]);
}
cout<<tpsort();
return 0;
}
负环
void spfa(){
queue<int>q;
for(int i=1;i<=n;i++){
dis[i]=INF;
}memset(vis,0,sizeof(vis));
memset(getin,0,sizeof(getin));
q.push(1);vis[1]=1;dis[1]=0;
while(!q.empty()){
int f1=q.front();q.pop();
vis[f1]=0;
for(int i=head[f1];i;i=edge[i].next){
int to=edge[i].to;
if(dis[to]>dis[f1]+edge[i].w){
dis[to]=dis[f1]+edge[i].w;
if(!vis[to]){
getin[to]++;
vis[to]=1;
q.push(to);
}
if(getin[to]>n){
puts("YE5");flag=false;
return;
}
}
}
}
}
树链剖分
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 1e5+7;
typedef long long ll;
struct node{
int l,r;
ll sum,lazy;
#define lazy(x) tr[x].lazy
#define v(x) tr[x].sum
#define lch(x) x<<1
#define rch(x) x<<1|1
}tr[maxn*4];
struct no{
int to,next;
}edge[maxn*4];
int cnt,head[maxn];
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
int n,m,r,mod,dfn[maxn];
int top[maxn],tot[maxn],sz[maxn],f[maxn],dep[maxn],son[maxn],num[maxn];
void pushup(int k){v(k)=(v(lch(k))+v(rch(k)))%mod;}
void pushdown(int k){
if(lazy(k)){
v(lch(k))=(v(lch(k))+lazy(k)*(tr[lch(k)].r-tr[lch(k)].l+1))%mod;
v(rch(k))=(v(rch(k))+lazy(k)*(tr[rch(k)].r-tr[rch(k)].l+1))%mod;
lazy(lch(k))=(lazy(lch(k))+lazy(k));
lazy(rch(k))=(lazy(rch(k))+lazy(k));
lazy(k)=0;
}
}
void dfs1(int u,int fa){
f[u]=fa;dep[u]=dep[fa]+1;sz[u]=1;
for(int i=head[u];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa)continue;
dfs1(to,u);sz[u]+=sz[to];
if(sz[son[u]]<sz[to])son[u]=to;
}
}
void dfs2(int u,int ftop){
dfn[u]=++dfn[0];
tot[dfn[u]]=u;
top[u]=ftop;
if(!son[u])return;
dfs2(son[u],ftop);
for(int i=head[u];i;i=edge[i].next){
int to=edge[i].to;
if(!dfn[to])dfs2(to,to);
}
}
void build(int k,int l,int r){
tr[k].l=l;
tr[k].r=r;
if(l==r){
v(k)=num[tot[l]];
return;
}
int mid=l+r>>1;
build(lch(k),l,mid);
build(rch(k),mid+1,r);
pushup(k);
}
void SegAdd(int k,int x,int y,ll sum){
if(tr[k].l>=x&&tr[k].r<=y){
v(k)=(v(k)+(tr[k].r-tr[k].l+1)*sum)%mod;
lazy(k)=(lazy(k)+sum)%mod;
return;
}pushdown(k);
int mid=tr[k].l+tr[k].r>>1;
if(x<=mid)SegAdd(lch(k),x,y,sum);
if(y>mid) SegAdd(rch(k),x,y,sum);
pushup(k);
}
ll SegQuery(int k,int x,int y){
if(tr[k].l>=x&&tr[k].r<=y)return v(k)%mod;
pushdown(k);
int mid=tr[k].l+tr[k].r>>1;ll ret=0;
if(x<=mid) ret=(ret+SegQuery(lch(k),x,y))%mod;
if(y>mid) ret=(ret+SegQuery(rch(k),x,y))%mod;
return ret;
}
void TreeAdd(int st,int en,ll sum){
while(top[st]!=top[en]){
if(dep[top[st]]<dep[top[en]])swap(st,en);
SegAdd(1,dfn[top[st]],dfn[st],sum);
st=f[top[st]];
}if(dep[st]>dep[en])swap(st,en);
SegAdd(1,dfn[st],dfn[en],sum);
}
ll TreeQuery(int st,int en){
ll ret=0;
while(top[st]!=top[en]){
if(dep[top[st]]<dep[top[en]])swap(st,en);
ret=(ret+SegQuery(1,dfn[top[st]],dfn[st]))%mod;
st=f[top[st]];
}if(dep[st]>dep[en])swap(st,en);
ret=(ret+SegQuery(1,dfn[st],dfn[en]))%mod;
return ret;
}
int main(){
scanf("%d%d%d%d",&n,&m,&r,&mod);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
for(int i=1;i<=n-1;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,dfn[0]);
for(int i=1;i<=m;i++){
int opt,x,y;ll z;
scanf("%d%d",&opt,&x);
if(opt==1){
scanf("%d%lld",&y,&z);
TreeAdd(x,y,z);
}else if(opt==2){
scanf("%d",&y);
printf("%lld\n",TreeQuery(x,y));
}else if(opt==3){
scanf("%lld",&z);
SegAdd(1,dfn[x],dfn[x]+sz[x]-1,z);
}else{
printf("%lld\n",SegQuery(1,dfn[x],dfn[x]+sz[x]-1));
}
}
return 0;
}
Dinic
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 100007;
const int INF = 2147483647;
int n,m,s,t;
struct node{
int to,next;
ll flow;
}edge[maxn*4];
int cnt,head[maxn];
void add(int from,int to,ll w){
edge[++cnt].to=to;
edge[cnt].next=head[from];
edge[cnt].flow=w;
head[from]=cnt;
}
int dep[maxn],cur[maxn];
ll Dinic(int u,ll rest){
ll ret=0,f=0;
if(u==t||rest==0)return rest;
for(int &i=cur[u];i!=-1;i=edge[i].next){
node &e=edge[i];
if(dep[e.to]==dep[u]+1 && (f=Dinic(e.to,min(rest,e.flow)))>0){
e.flow-=f;
edge[i^1].flow+=f;
ret+=f;rest-=f;
if(rest==0)return ret;
}
}
return ret;
}
int vis[maxn];
bool spfa(){
queue<int>q;
memset(vis,0,sizeof(vis));
q.push(s);vis[s]=1;dep[s]=1;
while(!q.empty()){
int f1=q.front();q.pop();
for(int i=head[f1];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(!vis[to]&&edge[i].flow>0){
vis[to]=1;
dep[to]=dep[f1]+1;
q.push(to);
}
}
}
return vis[t];
}
void MF(){
ll ans=0 ;
while(spfa()){
for(int i=1;i<=n;i++)cur[i]=head[i];
ans+=Dinic(s,INF);
}
printf("%lld",ans);
}
int main(){
memset(head,-1,sizeof(head));cnt=-1;
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++){
int x,y;ll z;scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);add(y,x,0);
}
MF();
}
矩阵快速幂
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 107;
const int mod = 1e9+7;
typedef long long ll;
struct M{
int len;
ll c[maxn][maxn];
friend M operator*(M a,M b){
M c;c.len=a.len;
memset(c.c,0,sizeof(c.c));
for(int i=1;i<=a.len;i++){
for(int j=1;j<=a.len;j++){
for(int l=1;l<=a.len;l++){
c.c[i][j]=(c.c[i][j]+a.c[i][l]*b.c[l][j])%mod;
}
}
}
return c;
}
};
int n;
ll k;
M POW(M a,ll times){
if(times==1){
return a;
}else {
M ret=POW(a,times/2);
ret=ret*ret;
if(times%2)ret=ret*a;
return ret;
}
}
M st;
int main(){
scanf("%d%lld",&n,&k);st.len=n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&st.c[i][j]);
}
}
st=POW(st,k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<st.c[i][j]<<" ";
}
cout<<endl;
}
}
Lucas定理
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
ll p;
ll ksm(ll a,ll b){
if(b==0)return 1;
else{
ll ret=ksm(a,b/2);
ret=(ret*ret)%p;
if(b%2)ret=(ret*a)%p;
return ret;
}
}
ll C(ll n,ll m){
ll ret=1,ret2=1;
for(ll i=n-m+1;i<=n;i++)ret=(ret*i)%p;
for(ll i=1;i<=m;i++)ret2=(ret2*i)%p;
return ret*ksm(ret2,p-2);
}
ll lucas(ll n,ll m){
if(!n||!m)return 1;
return (C(n%p,m%p)%p*lucas(n/p,m/p)%p)%p;
}
int main(){
int T;
scanf("%lld",&T);
while(T--){
ll n,m;
scanf("%lld%lld%lld",&n,&m,&p);
printf("%lld\n",lucas(n+m,m)%p);
}
}
AC自动机
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 5e6+7;
int ch[maxn][26],cnt;
int n,end[maxn];
void putin(string a){
int root=0;
for(int i=0;i<a.length();i++){
if(!ch[root][a[i]-'a'])ch[root][a[i]-'a']=++cnt;
root=ch[root][a[i]-'a'];
}
end[root]++;
}
int last[maxn],f[maxn];
void getfail(){
queue<int>q;f[0]=0;
for(int i=0;i<26;i++)
if(ch[0][i])f[ch[0][i]]=0,q.push(ch[0][i]);
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<26;i++){
int u=ch[now][i];
if(!u)ch[now][i]=ch[f[now]][i];
else q.push(u),f[u]=ch[f[now]][i];
}
}
}
void find(string a){
int len=a.length();
int j=0,ans=0;
for(int i=0;i<len;i++){
j=ch[j][a[i]-'a'];
for(int t=j;t&&~end[t];t=f[t])ans+=end[t],end[t]=-1;
}
cout<<ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
string into;
cin>>into;
putin(into);
}
getfail();
string T;
cin>>T;
find(T);
return 0;
}
倍增LCA
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 500007;
struct node{
int to,next;
}edge[maxn*2];
int cnt,head[maxn];
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
int n,m,rt,f[maxn][21],dep[maxn];
void dfs(int u,int fa){
dep[u]=dep[fa]+1;f[u][0]=fa;
for(int i=1;i<=log2(dep[u]);i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa)continue;
dfs(to,u);
}
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=log2(dep[u]-dep[v]);i>=0;i--)
if(dep[f[u][i]]>=dep[v])u=f[u][i];
if(u==v)return u;
for(int i=log2(dep[u]);i>=0;i--)
if(f[u][i]^f[v][i])
u=f[u][i],
v=f[v][i];
return f[u][0];
}
int main(){
scanf("%d%d%d",&n,&m,&rt);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}dfs(rt,0);
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",LCA(x,y));
}
return 0;
}
权值线段树和线段树合并
int merge(int u,int v){
if(!u || !v) return u+v;
int t=++cnt;
sum[t]=sum[u]+sum[v];
ls[t]=merge(ls[u],ls[v]);
rs[t]=merge(rs[u],rs[v]);
return t;
}
void merge(int &rt1,int &rt2,int l,int r){
if(!rt1||!rt2){rt1+=rt2;return;}
int mid=l+r>>1;
if(l==r){tr[rt1].v=1;return;}
merge(lch(rt1),lch(rt2),l,mid);
merge(rch(rt1),rch(rt2),mid+1,r);
pushup(rt1);
}
LCT
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define lch(x) c[x][0]
#define rch(x) c[x][1]
using namespace std;
const int maxn = 300005;
int n,m,val[maxn],c[maxn][2],fa[maxn],s[maxn],lazy[maxn],st[maxn];
inline int read(){
int f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
void pushr(int k){swap(c[k][1],c[k][0]);lazy[k]^=1;}
bool notroot(int x) { return c[fa[x]][1]==x||c[fa[x]][0]==x; }
void pushdown(int k){
if(lazy[k]){
lazy[k]^=1;
lazy[c[k][0]]^=1;
lazy[c[k][1]]^=1;
swap(c[k][0],c[k][1]);
}
}
void pushup(int k){s[k]=s[lch(k)]^s[rch(k)]^val[k];}
void rotete(int x){
int y=fa[x],z=fa[y],k=c[y][1]==x,w=c[x][!k];
if(notroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
pushup(y);
}
void splay(int x){
int cnt=0,x1=x,y,z;
st[++cnt]=x1;
while(notroot(x1))st[++cnt]=x1=fa[x1];
while(cnt)pushdown(st[cnt--]);
while(notroot(x)){
y=fa[x],z=fa[y];
if(notroot(y))
rotete((c[z][0]==y)^(c[y][0]==x)?x:y);
rotete(x);
}
pushup(x);return ;
}
void access(int x){
for(int y=0;x;y=x,x=fa[x])
splay(x),c[x][1]=y,pushup(x);
return;
}
void makeroot(int x){
access(x);
splay(x);
lazy[x]^=1;
}
void split(int x,int y){
makeroot(x);
access(y);splay(y);
}
int findroot(int x){
access(x);splay(x);
while(lch(x))pushdown(x),x=lch(x);
splay(x);return x;
}
void link(int x,int y){
makeroot(x);
if(findroot(y)==x)return;
fa[x]=y;
}
void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!c[y][0])
fa[y]=c[x][1]=0,pushup(x);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)val[i]=read();
for(int i=1;i<=m;i++){
int type,x,y;
type=read(),x=read(),y=read();
switch(type){
case 0:split(x,y);printf("%d\n",s[y]);break;
case 1:link(x,y);break;
case 2:cut(x,y);break;
case 3:splay(x);val[x]=y,pushup(x);
}
}
return 0;
}
最小生成树Kruskal
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 1000005;
int n,m;
struct node{
int x,y;
long long z;
}a[maxn];
int zu[maxn*2];
int find(int x){return zu[x]==x?x:zu[x]=find(zu[x]);}
void kruskal(){
for(int i=1;i<=n;i++)zu[i]=i;
int f1,f2,k=0;
long long ans=0;
for(int i=1;i<=m;i++){
f1=find(a[i].x);
f2=find(a[i].y);
if(f1!=f2){
zu[f1]=f2;k++;
ans+=a[i].z;
}
if(k==n-1){
cout<<ans;
break;
}
}
}
bool comp(node a,node b){return a.z<b.z;}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>a[i].x>>a[i].y>>a[i].z;
sort(a+1,a+m+1,comp);
kruskal();
}
Splay
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 101001;
const int INF = 2147483647;
int n,m,ch[maxn][2],root,fa[maxn],size[maxn],lazy[maxn];
void pushup(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;}
void pushdown(int x){
if(lazy[x]){
swap(ch[x][0],ch[x][1]);
lazy[ch[x][0]]^=1;
lazy[ch[x][1]]^=1;
lazy[x]=0;
}
}
void rotate(int x,int &k){
int y=fa[x];
int z=fa[y];
int kind;
if(ch[y][0]==x)kind=1;
else kind=0;
if(y==k)k=x;
else{
if(ch[z][0]==y)ch[z][0]=x;
else ch[z][1]=x;
}
ch[y][kind^1]=ch[x][kind];fa[ch[y][kind^1]]=y;
ch[x][kind]=y;fa[y]=x;fa[x]=z;
pushup(x);pushup(y);
}
void splay(int x,int &k){
while(x!=k){
int y=fa[x];
int z=fa[y];
if(y!=k){
if((ch[y][0]==x)^(ch[z][0]==y))rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
int find(int x,int k){
pushdown(x);
int s=size[ch[x][0]];
if(k==s+1)return x;
if(k<=s)return find(ch[x][0],k);
else return find(ch[x][1],k-s-1);
}
void work(int l,int r){
int x=find(root,l);
int y=find(root,r+2);
splay(x,root);
splay(y,ch[x][1]);
lazy[ch[y][0]]^=1;
}
void build(int l,int r,int f){
if(l>r)return;
int mid=(l+r)/2;
if(mid<f)ch[f][0]=mid;
else ch[f][1]=mid;
fa[mid]=f;size[mid]=1;
if(l==r)return;
build(l,mid-1,mid);
build(mid+1,r,mid);
pushup(mid);
}
int main()
{
cin>>n>>m;
root=(n+3)/2;
build(1,n+2,root);
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
work(l,r);
}
for(int i=2;i<=n+1;i++)printf("%d ",find(root,i)-1);
}
int get(int x){
return son[fa[x]][1]==x;
}
void rotate(int x){
int f=fa[x],ff=fa[f],w=get(x);
son[f][w]=son[x][w^1];
fa[son[f][w]]=f;
son[x][w^1]=f;
fa[f]=x;
fa[x]=ff;
if(ff){
son[ff][son[ff][1]==f]=x;
}
update(f);
update(x);
}
void update(int x){
if(x!=0){
siz[x]=cnt[x];
if(son[x][0])
siz[x]+=siz[son[x][0]];
if(son[x][1])
siz[x]+=siz[son[x][1]];
}
}
void splay(int x){
for(int f;f=fa[x];rotate(x)){
if(fa[f]){
rotate(get(x)==get(f)?f:x);
}
}
}
void insect(int v){
if(sz==0){
sz++;
son[1][1]=son[1][0]=fa[1]=0;
siz[1]=cnt[1]=1;
root=1;
key[1]=v;
return;
}
int now=root,f=0;
while(1){
if(key[now]==v){
cnt[now]++;
update(now);
update(f);
splay(now);
break;
}
f=now;
now=son[now][v>key[now]];
if(now==0){
sz++;
son[sz][1]=son[sz][0]=0;
fa[sz]=f;
siz[sz]=cnt[sz]=1;
son[f][v>key[now]]=sz;
key[sz]=v;
update(f);
splay(sz);
break;
}
}
}
int find(int v){
int ans=0,now=root;
while(1){
if(v<key[now]){
now=son[now][0];
}
else{
ans+=(son[now][0]!=0?siz[son[now][0]]:0);
if(v==key[now]){
splay(now);
return ans+1;
}
ans+=cnt[now];
now=son[now][1];
}
}
}
int findx(int x){
int now=root;
while(1){
if(son[now][0]!=0&&siz[son[now][0]]>=x){
now=son[now][0];
}
else{
int less=(son[now][0]!=0?siz[son[now][0]]:0)+cnt[now];
if(x<=less)
return key[now];
x-=less;
now=son[now][1];
}
}
}
int query_pre(int x){
splay(x);
int now=son[root][0];
while(son[now][1]!=0)now=son[now][1];
return now;
}
int query_next(int x){
splay(x);
int now=son[root][1];
while(son[now][0]!=0)now=son[now][0];
return now;
}
void clear(int x){
son[x][0]=son[x][1]=fa[x]=siz[x]=key[MX]=cnt[x]=0;
}
void del(int v){
find(v);
if(cnt[root]>1){
cnt[root]--;
update(root);
return;
}
if(son[root][0]==0&&son[root][1]==0){
clear(root);
root=0;
return;
}
if(son[root][0]==0){
int old=root;
root=son[root][1];
fa[root]=0;
clear(old);
return;
}
if(son[root][1]==0){
int old=root;
root=son[root][0];
fa[root]=0;
clear(old);
return;
}
int newroot=query_per(root),oldroot=root;
splay(newroot);
fa[son[oldroot][1]]=newroot;
son[root][1]=son[oldroot][1];
clear(oldroot);
update(root);
}
线段树
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100007;
typedef long long ll;
struct node{
ll val;
int l,r,length;
#define v(x) tr[x].val
#define lch(x) x<<1
#define rch(x) x<<1|1
#define lc(x) tr[x].l
#define rc(x) tr[x].r
}tr[maxn*4];
ll addlazy[maxn*4],mullazy[maxn*4],val[maxn],mod;
int n,m;
void pushup(int k){v(k)=v(lch(k))+v(rch(k))%mod;}
void pushdown(int k){
v(lch(k))=(v(lch(k))*mullazy[k])%mod;
v(lch(k))=(v(lch(k))+addlazy[k]*tr[lch(k)].length)%mod;
v(rch(k))=(v(rch(k))*mullazy[k])%mod;
v(rch(k))=(v(rch(k))+addlazy[k]*tr[rch(k)].length)%mod;
addlazy[lch(k)]=(addlazy[lch(k)]*mullazy[k]+addlazy[k])%mod;
addlazy[rch(k)]=(addlazy[rch(k)]*mullazy[k]+addlazy[k])%mod;
mullazy[lch(k)]=(mullazy[lch(k)]*mullazy[k])%mod;
mullazy[rch(k)]=(mullazy[rch(k)]*mullazy[k])%mod;
addlazy[k]=0;
mullazy[k]=1;
}
void add(int k,int l,int r,ll num){
if(lc(k)>=l&&rc(k)<=r){
v(k)=(v(k)+num*tr[k].length)%mod;
addlazy[k]+=num;
return ;
}
pushdown(k);
int mid=lc(k)+rc(k)>>1;
if(l<=mid)add(lch(k),l,r,num);
if(r>mid) add(rch(k),l,r,num);
pushup(k);
}
void mul(int k,int l,int r,ll num){
if(lc(k)>=l&&rc(k)<=r){
v(k)=(v(k)*num)%mod;
addlazy[k]=(addlazy[k]*num)%mod;
mullazy[k]=(mullazy[k]*num)%mod;
return ;
}
pushdown(k);
int mid=lc(k)+rc(k)>>1;
if(l<=mid)mul(lch(k),l,r,num);
if(r>mid) mul(rch(k),l,r,num);
pushup(k);
}
ll query(int k,int l,int r){
if(lc(k)>=l&&rc(k)<=r)
return v(k)%mod;
pushdown(k);
int mid=lc(k)+rc(k)>>1;
ll ret=0;
if(l<=mid)ret+=query(lch(k),l,r);
if(r>mid) ret+=query(rch(k),l,r);
return ret%mod;
}
void build(int k,int l,int r){
lc(k)=l;rc(k)=r;
mullazy[k]=1;
tr[k].length=r-l+1;
if(l==r){
v(k)=val[l];
return;
}
int mid=l+r>>1;
build(lch(k),l,mid);
build(rch(k),mid+1,r);
pushup(k);
}
int main(){
scanf("%d%d%lld",&n,&m,&mod);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
}
build(1,1,n);
for(int i=1;i<=m;i++){
int opt,l,r;
ll num;
scanf("%d%d%d",&opt,&l,&r);
if(opt==2){
scanf("%lld",&num);
add(1,l,r,num);
}
else if(opt==1){
scanf("%lld",&num);
mul(1,l,r,num);
}
else{
printf("%lld\n",query(1,l,r)%mod);
}
}
return 0;
}
点双联通分量
#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
struct edge
{
int to,pre;
}edges[1000001];
int head[1000001],dfn[1000001],dfs_clock,tot;
int num;
int stack[1000001],top;
vector<int>bcc[1000001];
int tarjan(int u,int fa){
int lowu=dfn[u]=++dfs_clock;
for(int i=head[u];i;i=edges[i].pre)
if(!dfn[edges[i].to]){
stack[++top]=edges[i].to;
int lowv=tarjan(edges[i].to,u);
lowu=min(lowu,lowv);
if(lowv>=dfn[u])
num++;
while(stack[top]!=edges[i].to)
bcc[num].push_back(stack[top--]);
bcc[num].push_back(stack[top--]);
bcc[num].push_back(u);
}
}
else if(edges[i].to!=fa)
lowu=min(lowu,dfn[edges[i].to]);
return lowu;
}
void add(int x,int y)
edges[++tot].to=y;
edges[tot].pre=head[x];
head[x]=tot;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]){
stack[top=1]=i;
tarjan(i,i);
}
for(int i=1;i<=num;i++){
printf("BCC#%d: ",i);
for(int j=0;j<bcc[i].size();j++)
printf("%d ",bcc[i][j]);
printf("\n");
}
return 0;
}
桥以及强连通分量
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
queue < int > q;
const int maxn = 100010;
int head[maxn];
struct node{
int to;
int next;
}edge[5*maxn];
int n,m;
int cnt=1;
int instack[maxn];
int co[maxn];
int num[maxn];
int dfn[maxn],low[maxn];
int visn=1;
int stack[maxn];
int top=0;
int sum=0;
int cd[maxn];
int used[maxn];
void add(int from,int to){
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt++;
}
void work(){
cin>>n>>m;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
add(x,y);
}
return ;
}
void tarjan(int u){
instack[u]=1;
dfn[u]=low[u]=visn++;
stack[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[v],low[u]);
}
else if(instack[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
sum++;
int v;
do{
v=stack[top--];
co[v]=sum;
num[sum]++;
}while(v!=u);
}
}
int main(){
work();
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i);
}
}
欧拉筛以及莫比乌斯函数
void work(){
u[1]=1;vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++tot]=i;
u[i]=-1;
}
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
vis[prime[j]*i]=1;
if(i%prime[j]==0)break;
u[prime[j]*i]=-u[i];
}
}
}
treap
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 100007;
typedef long long ll;
int sz[maxn],cov[maxn];
ll num[maxn],ran[maxn];
int ch[maxn][2],m,tot;
const int INF = 2147483647;
#define lch(x) ch[x][0]
#define rch(x) ch[x][1]
int root;int mod=20030625;
void pushup(int k){sz[k]=sz[lch(k)]+sz[rch(k)]+cov[k];}
int New(ll val){
ran[++tot]=(rand()*rand())%mod;
num[tot]=val;cov[tot]=sz[tot]=1;
return tot;
}
void zig(int &k){
int y=rch(k);rch(k)=lch(y);
lch(y)=k;sz[y]=sz[k];
pushup(k);k=y;
}
void zag(int &k){
int y=lch(k);lch(k)=rch(y);
rch(y)=k;sz[y]=sz[k];
pushup(k);k=y;
}
void insert(int &k,ll val){
if(!k){k=New(val);return;}
if(num[k]==val){cov[k]++;pushup(k);return;}
else if(num[k]<val){
insert(rch(k),val);
if(ran[rch(k)]<ran[k])zig(k);
}else{
insert(lch(k),val);
if(ran[lch(k)]<ran[k])zag(k);
}
pushup(k);
}
void Del(int &k,ll val){
if(!k)return;
if(num[k]==val){
if(cov[k]>1){cov[k]--;pushup(k);return;}
if(!lch(k)||!rch(k))k=lch(k)+rch(k);
else if(ran[lch(k)]<ran[rch(k)])zag(k),Del(k,val);
else zig(k),Del(k,val);
}
else if(num[k]>val)Del(lch(k),val);
else Del(rch(k),val);
pushup(k);
}
ll QueryFro(ll val){
int k=root;ll ret=0;
while(k){
if(!k)return 0;
else if(val>num[k])ret=num[k],k=rch(k);
else k=lch(k);
}return ret;
}
ll QueryPas(ll val){
int k=root;ll ret=0;
while(k){
if(!k)return 0;
else if(val<num[k])ret=num[k],k=lch(k);
else k=rch(k);
}return ret;
}
int QueryNumberRank(ll val){
int k=root,ret=0;
while(k){
if(!k)return 0;
if(num[k]==val)return (sz[lch(k)]+1+ret);
else if(num[k]>val) k=lch(k);
else ret+=sz[lch(k)]+cov[k],k=rch(k);
}
}
ll QueryRankNumber(ll R){
int k=root;
while(k){
if(!k)return 0;
if(sz[lch(k)]<R&&R<=sz[lch(k)]+cov[k])return num[k];
else if(R<=sz[lch(k)])k=lch(k);
else R-=(sz[lch(k)]+cov[k]),k=rch(k);
}
}
int n;
int main(){
srand(20030625);
insert(root,-INF);
insert(root,INF);
scanf("%d",&n);
for(int i=1;i<=n;i++){
int opt;ll val;scanf("%d%lld",&opt,&val);
if(opt==1){insert(root,val);}
else if(opt==2){Del(root,val);}
else if(opt==3){printf("%lld\n",QueryNumberRank(val)-1);}
else if(opt==4){printf("%lld\n",QueryRankNumber(val+1));}
else if(opt==5){printf("%lld\n",QueryFro(val));}
else {printf("%lld\n",QueryPas(val));}
}
return 0;
}
CDQ分治
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1000007;
int k,tr[maxn],n;
struct node{
int a,b,c,num,ans;
}task[maxn];
bool cmp1(node a,node b){
if(a.c==b.c)return (a.b==b.b)?a.a<b.a:a.b<b.b;
return a.c<b.c;
}
bool cmp2(node a,node b){return a.b==b.b?a.a<b.a:a.b<b.b;}
int lowbit(int x){return x&-x;}
void add(int x,int num){
for(;x<=k;x+=lowbit(x))tr[x]+=num;
}
int query(int x){
int ret=0;
for(;x;x-=lowbit(x))ret+=tr[x];
return ret;
}
int ans[maxn];
void cdq(int l,int r){
if(l==r)return;
int mid=l+r>>1;
cdq(l,mid),cdq(mid+1,r);
sort(task+l,task+1+mid,cmp2);
sort(task+mid+1,task+1+r,cmp2);
int i=mid+1,j=l;
for(;i<=r;i++){
while(task[i].b>=task[j].b&&j<=mid)
add(task[j].a,task[j].num),j++;
task[i].ans+=query(task[i].a);
}
for(i=l;i<j;i++)
add(task[i].a,-task[i].num);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&task[i].a,&task[i].b,&task[i].c);
}sort(task+1,task+1+n,cmp1);
int nn=n,sum=0;n=0;
for(int i=1;i<=nn;i++){
sum++;
if(task[i].a!=task[i+1].a || task[i].b!=task[i+1].b || task[i].c!=task[i+1].c){
task[++n]=(node){task[i].a,task[i].b,task[i].c,sum,0},sum=0;
}
}
cdq(1,n);
for(int i=1;i<=n;i++){
ans[task[i].ans+task[i].num-1]+=task[i].num;
}
for(int i=0;i<nn;i++)
printf("%d\n",ans[i]);
return 0;
}
最长公共子序列
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 100007;
int lowbit(int x){return x&-x;}
int tr[maxn],n,a[maxn],b[maxn],c[maxn],ans;
int query(int x){
int ret=0;
for(;x;x-=lowbit(x))ret=max(ret,tr[x]);
return ret;
}
void add(int x,int num){
for(;x<=n;x+=lowbit(x)){
tr[x]=max(tr[x],num);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
c[a[i]]=i;
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
b[i]=c[b[i]];
}
for(int i=1;i<=n;i++){
int len=query(b[i]-1)+1;
ans=max(ans,len);
add(b[i],len);
}
cout<<ans;
}
EK费用流
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 50007;
const int INF = 2147483647;
struct node{
int to,next,flow,w;
}edge[maxn*3];
int cnt,head[maxn];
void add(int from,int to,int flow,int w){
edge[++cnt].to=to;
edge[cnt].flow=flow;
edge[cnt].w=w;
edge[cnt].next=head[from];
head[from]=cnt;
}
int n,m,d[maxn],g[maxn],vis[maxn],pre[maxn];
int last[maxn];
bool EK_spfa(int s,int t){
for(int i=1;i<=n;i++)d[i]=g[i]=INF;
queue<int>q;vis[s]=1;q.push(s);d[s]=0;
memset(vis,0,sizeof(vis));
pre[t]=-1;
while(!q.empty()){
int f1=q.front();q.pop();
vis[f1]=0;
for(int i=head[f1];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(edge[i].flow&&edge[i].w+d[f1]<d[to]){
d[to]=d[f1]+edge[i].w;
g[to]=min(g[f1],edge[i].flow);
pre[to]=f1;last[to]=i;
if(!vis[to])vis[to]=1,q.push(to);
}
}
}
return pre[t]!=-1;
}
int ans=0,cost=0;
void MFMC(int s,int t){
while(EK_spfa(s,t)){
ans+=g[t];cost+=g[t]*d[t];
int now=t;
while(now!=s){
edge[last[now]].flow-=g[t];
edge[last[now]^1].flow+=g[t];
now=pre[now];
}
}
}
int s,t;
int main(){cnt=-1;
memset(head,-1,sizeof(head));
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++){
int x,y,f,w;
scanf("%d%d%d%d",&x,&y,&f,&w);
add(x,y,f,w);
add(y,x,0,-w);
}
MFMC(s,t);
printf("%d %d",ans,cost);
}
FFT
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 3e6+7;
const double Pi = acos(-1);
struct cp
{
double x,y;
cp(double xx=0.0,double yy=0.0)
{x=xx,y=yy;}
}a[maxn],b[maxn];
int len=1,bit,rev[maxn];
cp operator +(cp xxx,cp yyy){return cp(xxx.x+yyy.x,xxx.y+yyy.y);}
cp operator *(cp xxx,cp yyy){return cp(xxx.x*yyy.x-xxx.y*yyy.y,xxx.x*yyy.y+xxx.y*yyy.x);}
cp operator -(cp xxx,cp yyy){return cp(xxx.x-yyy.x,xxx.y-yyy.y);}
void FFT(cp a[],int type){
for(int i=0;i<len;i++) if(i<rev[i])swap(a[i],a[rev[i]]);
for(int h=1;h<len;h*=2){
cp wn(cos(Pi/h),type*sin(Pi/h));
for(int i=0;i<len;i+=(h*2)){
cp w(1,0);
for(int k=0;k<h;k++){
cp u=a[i+k],t=w*a[k+h+i];
a[i+k]=u+t;a[k+h+i]=u-t;w=w*wn;
}
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)scanf("%lf",&a[i].x);
for(int i=0;i<=m;i++)scanf("%lf",&b[i].x);
while(len<=(n+m))len<<=1,bit++;
for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
FFT(a,1);FFT(b,1);
for(int i=0;i<=len;i++)a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=0;i<=n+m;i++)printf("%d ",(int)(fabs(a[i].x)/len+0.5));
return 0;
}
单源最短路,当然不是spfa
void dij(int v0){
for(int i=1;i<=n;i++)dis[i]=INF;
q.push(make_pair(0,v0));dis[v0]=0;
while(!q.empty()){
int f1=q.top().first,f2=q.top().second;q.pop();
if(-dis[f2]!=f1)continue;
for(int i=head[f2];i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dis[to]>w+dis[f2]){
dis[to]=w+dis[f2];
q.push(make_pair(-dis[to],to));
}
}
}
}
动态开点主席树
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 2e5+7;
int n,m,tot,num[maxn],a[maxn],_hash[maxn],rt[maxn];
#define lch(x) ch[x][0]
#define rch(x) ch[x][1]
int ch[maxn*60][2],sum[maxn*60];
void build(int &k,int l,int r){
if(!k)k=++tot;int mid=l+r>>1;
sum[k]=0;if(l==r)return;
build(lch(k),l,mid);
build(rch(k),mid+1,r);
}
void update(int &k,int fa,int l,int r,int val){
if(!k)k=++tot;int mid=l+r>>1;
sum[k]=sum[fa]+1;if(l==r)return;
if(val<=mid)rch(k)=rch(fa),update(lch(k),lch(fa),l,mid,val);
else lch(k)=lch(fa),update(rch(k),rch(fa),mid+1,r,val);
}
int query(int k1,int k2,int l,int r,int Rank){
if(l==r)return l;
int mid=l+r>>1,sam=sum[lch(k2)]-sum[lch(k1)];
if(Rank<=sam) return query(lch(k1),lch(k2),l,mid,Rank);
else return query(rch(k1),rch(k2),mid+1,r,Rank-sam);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&num[i]),a[i]=num[i];
sort(a+1,a+1+n);int len=unique(a+1,a+1+n)-a-1;
for(int i=1;i<=n;i++)num[i]=lower_bound(a+1,a+1+len,num[i])-a;
build(rt[0],1,len);
for(int i=1;i<=n;i++)update(rt[i],rt[i-1],1,len,num[i]);
for(int i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
printf("%d\n",a[query(rt[x-1],rt[y],1,len,z)]);
}
}
快速幂
ll ksm(ll a,ll b){
if(b==0)return 1;
ll ret=ksm(a,b/2)%k;
ret=(ret*ret)%k;
if(b%2==1)ret=(ret*a)%k;
return ret%k;
}
KMP
void prework(){
int j=0;
for(int i=2;i<=m;i++){
while(j&&ch2[j+1]!=ch2[i])j=p[j];
if(ch2[j+1]==ch2[i])j++;
p[i]=j;
}
}
void KMP(){
int j=0,ans=0;
for(int i=1;i<=n;i++){
while(j&&ch2[j+1]!=ch1[i])j=p[j];
if(ch2[j+1]==ch1[i])j++;
if(j==m)j=p[j],printf("%d\n",i-m+1);
}
for(int i=1;i<=m;i++)cout<<p[i]<<" ";
}