赛用模板(数据结构)

树状数组

int tr[N],n;
void update(int pos,int val){
    while(pos<=n){
        tr[pos]+=val;
        pos+=pos&(-pos);
    }
}
int query(int l,int r){
    int ansl=0,ansr=0;l--;
    while(l>0){
        ansl+=tr[l];
        l-=l&(-l);
    }
    while(r>0){
        ansr+=tr[r];
        r-=r&(-r);
    }
    return ansr-ansl;
}

线段树(单点更新)

int tr[4*N];//区间最大值,操作为单点加

void update(int rt,int L,int R,int pos,int val){
    if(L==R){
        tr[rt]=f;return;
    }
    int mid=L+R>>1;
    if(pos<=mid)update(rt,L,mid,pos,val);
    else update(rt,mid+1,R,pos,val);
    tr[rt]=max(tr[ls],tr[rs]);
}

int Query(int rt,int L,int R,int l,int r){
    if(y>=r&&x<=l)return tr[rt];
    int mid=l+r>>1;
    int ans=0;
    if(l<=mid)ans=Query(ls,L,mid,l,r);
    if(r>mid)ans=max(ans,Query(ts,mid+1,R,l,r));
    return ans;
}

线段树(区间更新)

int tr[N*4];//区间最大值,操作为区间加
int f[N*4];//懒惰标记,有标记说明下面的没有推下去

void down(int rt){
    if(!f[rt])return;
    f[ls]+=f[rt];f[rs]+=f[rt];
    tr[ls]+=f[rt],tr[rs]+=f[rt];
    f[rt]=0;
}
void update(int rt,int L,int R,int l,int r,int val){//rt[L,R] 操作为[l,r]+val
    if(R<=r&&L>=l){
        tr[rt]+=val;f[rt]+=val;return;
    }
    down(rt);
    int mid=R+L>>1;
    if(l<=mid)update(ls,L,mid,l,r,val);
    if(r>mid)update(rs,mid+1,R,l,r,val);
    tr[rt]=max(tr[ls],tr[rs]);
}
int query(int rt,int L,int R,int l,int r){//rt[L,R] 操作为[l,r]最大值
    if(r>=R&&l<=L){return tr[rt];}
    down(rt);
    int ans=0;
    int mid=R+L>>1;
    if(l<=mid)ans=query(ls,L,mid,l,r);
    if(r>mid)ans=max(ans,query(rs,mid+1,R,l,r));
    return ans;
}

矩阵

#define MOD ((int)1e9+7)
struct matrix{
    int size;
    LL mat[N][N];
    matrix(int s){
        size=s;memset(mat,0,sizeof(mat));
    }void init(){
        for(int i=1;i<=size;i++){
            for(int j=1;j<=size;j++){
                scanf("%lld",&mat[i][j]);
            }
        }
    }void out(){
        for(int i=1;i<=size;i++){
            for(int j=1;j<=size;j++){
                printf("%lld ",mat[i][j]);
            }printf("\n");
        }
    }matrix operator * (const matrix & x)const{
        matrix ans(x.size);
        for(int i=1;i<=x.size;i++){
            for(int j=1;j<=x.size;j++){
                for(int k=1;k<=x.size;k++){
                    ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*x.mat[k][j])%MOD;
                }
            }
        }return ans;
    }
} ;
matrix swift(matrix a,int t){
    matrix ans(a.size);
    for(int i=1;i<=a.size;i++)ans.mat[i][i]=1;
    while(t){
        if(t&1)ans=ans*a;
        a=a*a;t>>=1;
    }return ans;
}

带权并查集

int fa[maxn],v[maxn];
//v[i]表示i比root大多少
int fi(int a){
    if(fa[a]==a)return a;
    int tmp=fa[a];
    fa[a]=fi(fa[a]);
    v[a]+=v[tmp];
    return fa[a];
}

int un(int a,int b,int s){//返回1表示矛盾
    int f1=fi(a),f2=fi(b);
    if(f1==f2){
        if(s+v[b]==v[a])return 0;
        return 1;
    }
    fa[f1]=f2;v[f1]=s+v[b]-v[a];
    return 0;
}

LCA

int head[100009];
int to[400009],nex[400009],v[400009];
int now;
void add(int a,int b,int c1,int c2){
    to[++now]=b;v[now]=c1;nex[now]=head[a];head[a]=now;
    to[++now]=a;v[now]=c2;nex[now]=head[b];head[b]=now;
}
///////
int up[100009],down[100009];//up:点到root的距离  ,  down:root到点的距离   双向边
int fa[100009];
int deep[100009];//lca用到的深度
void dfs(int p,int f,int t){
    fa[p]=f;deep[p]=t;//lca要求fa和deep,题目要求up和down
    for(int i=head[p];~i;i=nex[i]){
        int b=to[i];
        if(b==f)up[p]=up[f]+v[i];
    }
    for(int i=head[p];~i;i=nex[i]){//和up分开,要不然up会出错
        int b=to[i];
        if(b!=f){
            down[b]=down[p]+v[i];
            dfs(b,p,t+1);
        }
    }
}
///////
int p[100009][30];
void init(int n){//预处理i的2^k次祖先
    mmm(p,-1);
    for(int i=1;i<=n;i++)p[i][0]=fa[i];
    for(int i=1;;i++){
        int bre=1;
        for(int j=1;j<=n;j++){
            if(~p[j][i-1]){
                bre=0;p[j][i]=p[p[j][i-1]][i-1];
            }
        }
        if(bre)break;
    }
}

int lca(int a,int b){
    if(deep[a]>deep[b])swap(a,b);
    int i;
    for(i=0;(1<<i)<deep[b];i++);i--;
    for(;;){
        if(deep[a]==deep[b])break;
        if(deep[b]-deep[a]<(1<<i))i--;
        else b=p[b][i];
    }
    for(i=0;(1<<i)<deep[b];i++);i--;
    for(;;){
        if(a==b)return a;
        if(fa[a]==fa[b])return fa[a];
        if(p[a][i]==p[b][i])i--;
        else a=p[a][i],b=p[b][i];
    }
}

int main(){
    int t=read();
    while(t--){
        int n=read();
        mmm(head,-1);now=0;
        int sum=0;
        for(int i=1;i<n;i++){
            int a,b,c1,c2;
            scanf("%d%d%d%d",&a,&b,&c1,&c2);
            add(a,b,c1,c2);sum+=c1+c2;
        }

        up[1]=down[1]=0;
        dfs(1,-1,1);
        init(n);

        ...
    }
}

树分治

const int N =10009;
int n,k;
int head[N],nex[2*N],to[2*N],from[2*N],v[2*N],now;
void add(int a,int b,int vv){
    to[++now]=b;v[now]=vv;from[now]=a;nex[now]=head[a];head[a]=now;
    to[++now]=a;v[now]=vv;from[now]=b;nex[now]=head[b];head[b]=now;
}

int ans;

int G;
int vis[N];//是否删除
int siz[N],maxn[N];//这棵子树大小,最大子树大小
void getG(int p,int fa,int sum){
    siz[p]=1;
    maxn[p]=0;
    for(int i=head[p];~i;i=nex[i]){
        if(!vis[to[i]]&&to[i]!=fa){
            getG(to[i],p,sum);//这个时候既可以得出G,又可以得出下面的siz
            siz[p]+=siz[to[i]];
            maxn[p]=max(maxn[p],siz[to[i]]);//找出最大子树
        }
    }
    maxn[p]=max(maxn[p],sum-siz[p]);//当然还要这棵树的上半部分比较
    if(maxn[G]>maxn[p])G=p;
}

int dep[N],num,len[N];
void dfs(int p,int fa){
    for(int i=head[p];~i;i=nex[i]){
        if(vis[to[i]]||fa==to[i])continue;
        len[++num]=dep[to[i]]=dep[p]+v[i];
        dfs(to[i],p);
    }
}
int cal(int p,int length){//重点,多加的部分的消除
    int sum=0;
    num=0;
    len[++num]=dep[p]=length;//自己也加进去
    dfs(p,0);//得出离G点距离
    sort(len+1,len+1+num);
    for(int l=1,r=num;r>l;){
        if(dep[r]+dep[l]<=k)sum+=r-l,l++;//r-l对可以匹配,l已经匹配完了
        else r--;//r已经不能匹配了
    }
    return sum;
}

void divide(int p){
    //printf("G==%d\n",p);
    vis[p]=1;
    ans+=cal(p,0);
    for(int i=head[p];~i;i=nex[i]){
        if(vis[to[i]])continue;
        ans-=cal(to[i],v[i]);
        G=0;//为了初始化
        maxn[0]=siz[to[i]];
        getG(to[i],0,siz[to[i]]);//一套做全都是0
        divide(G);
    }
}

int main(){
    while(cin>>n>>k){
        if(!n&&!k)break;
        ans=0;mmm(head,-1);now=0;mmm(vis,0);
        for(int i=1,a,b,v;i<n;i++)a=read(),b=read(),v=read(),add(a,b,v);
        maxn[0]=n;//因为在getG的时候可以和maxn[0]比较来初始化G(使第一个fa==0)
        G=0;getG(1,0,n);
        divide(G);
        printf("%d\n",ans);
    }
}

主席树(小于等于k的数量)

const int N=100009;
int rt[N<<2],ls[N<<2],rs[N<<2],cnt,siz[N<<2];
//每个点有个编号(同链式前向星),rt[2]=4表示第2次操作形成的树的根节点编号为4
//除了rt是操作:编号以外,ls和rs都是编号:编号(某个点(编号)的儿子的编号)
int arr[N],tmp[N];

void insert(int last,int now,int l,int r,int p){
    siz[now]=siz[last]+1;
    ls[now]=ls[last];
    rs[now]=rs[last];//直接连原来版本的儿子
    if(l==r) return ;
    int mid=l+r>>1;
    if(p<=mid)insert(ls[last],ls[now]=++cnt,l,mid,p);//需要更新才建新点当儿子
    else insert(rs[last],rs[now]=++cnt,mid+1,r,p);
}

int query(int p,int l,int r,int k){
    if(r<=k)return siz[p];
    int mid=l+r>>1;
    int ans=query(ls[p],l,mid,k);
    if(k>mid) ans+=query(rs[p],mid+1,r,k);
    return ans;
}

int main(){
    int t;scanf("%d",&t);
    int ca=0;
    while(t--){
        printf("Case %d:\n",++ca);
        cnt=0;memset(siz,0,sizeof(siz));
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);tmp[i]=arr[i];
        }
        sort(tmp+1,tmp+1+n);
        int tt=unique(tmp+1,tmp+1+n)-tmp-1;
        for(int i=1;i<=n;i++)insert(rt[i-1],rt[i]=++cnt,1,tt,lower_bound(tmp+1,tmp+1+tt,arr[i])-tmp);//离散化

        while(m--){
            int l,r,k;scanf("%d%d%d",&l,&r,&k);l++,r++;
            if(k>=tmp[tt])k=tt;
            else k=upper_bound(tmp+1,tmp+1+tt,k)-tmp-1;
            if(!k)printf("0\n");
            else printf("%d\n",query(rt[r],1,tt,k)-query(rt[l-1],1,tt,k));
        }
    }
}

主席树(第k大)

#define N 100005
int root[N];
int size[N*25],lchild[N*25],rchild[N*25];
int tot;
void insert(int last,int cur,int L,int R,int k) //单点更新
{
    size[cur]=size[last]+1;//将前一个树的信息复制过来
    lchild[cur]=lchild[last];
    rchild[cur]=rchild[last];
    if(L==R)return ;
    int mid=L+R>>1;
    if(k<=mid) insert(lchild[last],lchild[cur]=++tot,L,mid,k);//对于需要更改的节点都需要新增节点
    else insert(rchild[last],rchild[cur]=++tot,mid+1,R,k);
}
int query(int last,int cur,int k,int L,int R)
{
    if(L==R)return L;
    int mid=L+R>>1;
    int lsum=size[lchild[cur]]-size[lchild[last]];
    if(lsum>=k)return query(lchild[last],lchild[cur],k,L,mid);
    else return query(rchild[last],rchild[cur],k-lsum,mid+1,R);
}
int a[N],b[N],n,m,l,r,k;
map<int,int>mp;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        tot=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        int t=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;i++)insert(root[i-1],root[i]=++tot,1,t,lower_bound(b+1,b+t+1,a[i])-b);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",b[query(root[l-1],root[r],k,1,t)]);
        }
    }
}

KMP

void KMP(char *x,int *fail){
    int len=strlen(x);
    int i=0,j=-1;
    fail[0]=-1;
    while(i<len){
        while(j!=-1&&x[i]!=x[j]) j=fail[j];
        fail[++i]=++j;
        if(x[i]==x[j]) fail[i]=fail[j];
    }
}
int mina(){
	int len=strlen(a);//目标串(大串)
	int en=strlen(str);//模式串(小串)
    KMP(str,fail);
    int j=0;
    for(int i=0;i<len;i++){
        while(str[j]!=a[i]&&j!=-1)j=fail[j];
        j++;
        if(j==en){此小串完全匹配成功}
    }
}

AC自动机

#include<stdio.h>  
#include<string.h> 
#include<queue>  
#include<string>
#include<iostream>
#define maxlen 100005  
using namespace std; 
int n;
int nxt[maxlen][30],FAIL[maxlen],edd[maxlen],root,L;
//nxt记录节点,在这里edd指针代表以当前节点为字符串尾的字符串个数   
int mark[maxlen];
int newnode()  {  
    for(int i=0;i<26;i++)  
        nxt[L][i]=-1;//节点连接的边初始化为-1   
    edd[L]=0;  
    mark[L]=0;
    return L++;  
}  
void init()  {  
    L=0;  
    root=newnode();  
}  
void insert(char buf[],int l){//trie树的建立   
    int now=root;  
    for(int i=0;i<l;i++)  {  
        if(nxt[now][buf[i]-'a']==-1)nxt[now][buf[i]-'a']=newnode();  
        now=nxt[now][buf[i]-'a'];  
    }  
    edd[now]++;  
}  

void build(){//建立ac自动机   
    queue<int>que;  
    for(int i=0;i<26;i++)   {  
        if(nxt[root][i]==-1)nxt[root][i]=root;  
        else    {               //若有连边则将节点加入队列 ,并将FAIL指针指向root   
      		FAIL[nxt[root][i]]=root;  
            que.push(nxt[root][i]);  
        }  
    }  
    while(!que.empty())    {  
        int now=que.front();  
        que.pop();  
        for(int i=0;i<26;i++)  {  
            if(nxt[now][i]==-1)//若无连边,则将该边指向当前节点FAIL指针指向的相应字符连接的节点   
                nxt[now][i]=nxt[FAIL[now]][i];  
            else {  //若有连边,则将儿子节点的FAIL指针指向当前节点FAIL指针指向相应字符接的节点   
                FAIL[nxt[now][i]]=nxt[FAIL[now]][i];  
                que.push(nxt[now][i]); //加入队列继续遍历   
            }  
        }  
    }  
}  

int query(char buf[],int l) {  
    int now=root;  
    int res=0;  
    for(int i=0;i<l;i++)  {  
        now=nxt[now][buf[i]-'a'];  
        int temp=now;  
        while(temp!=root&&mark[temp]==0){  //根据题目要求改变形式   
            res+=edd[temp];  
            edd[temp]=0;  
            mark[temp]=1;
            temp=FAIL[temp];  
        }  
    }  
    return res; //在这里返回的是匹配到的模式串的数量   
}  

char buf[maxlen],ans[maxlen];
string A[maxlen];
int main(){
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        init();
        int ma=0;
        for(int i=0;i<n;i++)  {
            scanf("%s",buf);
            int l=strlen(buf);
            if(ma<l) {
                ma=l;
                strcpy(ans,buf);    
            }
            insert(buf,l);
        }
        build(); 
        int sum=query(ans,ma);
        if(sum==n) puts(ans);
        else puts("No");
    }
}

Splay

int ch[N][2],pre[N],cnt[N],size[N],key[N];
int tot,root;
int a[N],n;
void newnode(int &u,int fa,int KEY){
    u=++tot;
    ch[u][0]=ch[u][1]=0;
    pre[u]=fa;cnt[u]=size[u]=1;
    key[u]=KEY;
}
void up(int x){
     if(x)  {
          size[x]=cnt[x];
          if(ch[x][0])size[x]+=size[ch[x][0]];
          if(ch[x][1])size[x]+=size[ch[x][1]];
     }
}
void rotate(int u,int kind){//旋转 kind表示u在fa的哪一边
    int fa=pre[u];
    ch[fa][kind]=ch[u][!kind];
    pre[ch[u][!kind]]=fa;
    if(pre[fa])ch[pre[fa]][ch[pre[fa]][1]==fa]=u;
    pre[u]=pre[fa];
    ch[u][!kind]=fa;
    pre[fa]=u;
    up(fa);up(u);
}
void splay(int u,int goal){
    int fa,kind;
    while(pre[u]!=goal){
        if(pre[pre[u]]==goal) {
            rotate(u,R(pre[u])==u);
        }
        else {
            fa=pre[u];
            kind=R(pre[fa])==fa;
            if(ch[fa][kind]!=u) {//不在同一侧
                rotate(u,!kind);
                rotate(u,kind);
            }
            else   {
                rotate(fa,kind);
                rotate(u,kind);
            }
        }
    }
    up(u);
    if(goal==0)root=u;
}
void insert(int v){
    if(root==0)   {
        newnode(root,0,v);
        return;
    }
    int now=root,fa=0;
    while(1) {
        if(key[now]==v){
            cnt[now]++;up(now);up(fa);splay(now,0);
            break;
        }
        fa=now;
        now=ch[now][key[now]<v];
        if(now==0) {
            newnode(ch[fa][key[fa]<v],fa,v);
            up(fa);splay(ch[fa][key[fa]<v],0);
            break;
        }
    }
}


int getkth(int u,int k){//第k个键值的点的编号
    int s=size[L(u)]+cnt[u];
    if(size[L(u)]<k&&k<=s) return u;
    if(s-cnt[u]>=k) return getkth(L(u),k);
    else return getkth(R(u),k-s);
}
int find(int u,int x){//查找键值为x的点的编号
    if(key[u]==x)return u;
    if(key[u]>x) {
        if(!L(u))return -1;
        return find(L(u),x);
    }
    if(key[u]<x) {
        if(!R(u))return -1;
        return find(R(u),x);
    }
}
int getpre(int u){
	if(cnt[u]>=2)return u;
	u=L(u);
    while(R(u))u=R(u);
    return u;
}
int getnext(int u){
	if(cnt[u]>=2)return u;
    u=R(u);
    while(L(u))u=L(u);
    return u;
}
void del(int x){//删除编号为x的节点
    if(size[root]==1) {
        root=0;
        return ;
    }
    if(cnt[x]>1){
        cnt[x]--;
        return ;
    }
    splay(x,0);
    if(L(root))  {
        if(!R(root)) {
            pre[L(root)]=0;
            root=L(root);
            return ;
        }
        int p=getpre(x);
        splay(p,root);
        R(p)=R(root);
        pre[R(root)]=p;
        root=p;
        pre[p]=0;
        up(root);
    }
    else{
        root=R(root);
        pre[root]=0;
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/82787617