hdy未完成板子

一.基础算法

1.高精度

2.三分

dl f(dl x){
	
}

dl sf(dl l,dl r){
    dl mid,midr,ans;
    while (fabs(r-l)>eps) {
        mid=(l+r)/2;
        midr=(mid+r)/2;
        if(f(mid) > f(midr)) l=mid; else r=midr;   //求最小值
    } 
    ans=f(l);
    zz=l;
    return ans;
}

3.二分

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

二.数据结构

1.字典树

#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> pii;

const int N = 1e5+20;
int dx[]={1,-1,0,0,1,-1,1,-1};
int dy[]={0,0,1,-1,1,-1,-1,1};
queue<pii> q;
int n,m;
int a[N];
int tr[N*32][2],tot=1,res;
int read(int &n)
{
     char ch=' ';int q=0,w=1;
     for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
     if(ch=='-')w=-1,ch=getchar();
     for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;
     n=q*w;    return n;
}

void insert(int x)
{
	int p=1;
	for(int i=30;~i;i--)
	{
		int &s=tr[p][x>>i&1];
		if(!s) s=++idx;
		p=s; 
	}
}

int search(int x)
{
	int p=1,ans=0;
	for(int i=30;~i;i--)
	{
		int s=x>>i&1;
		if(tr[p][!s])
		{
			ans+=(1<<i);
			p=tr[p][!s];
		}
		else p=tr[p][s];
	}
	return ans;
}

int main() 
{
	int n;
	read(n);
	for(int i=1;i<=n;i++)	read(a[i]),insert(a[i]);
	for(int i=1;i<=n;i++)
	{
		res=max(res,search(a[i]));
	}
	printf("%d\n",ans);
	 
	
    
}

2.线段树

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5+10;

typedef long long ll;

int w[N];
int n,m;

struct node {
	int l,r;
	ll sum,add;
}tr[N*4];

void pushup(int u)
{
	tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}

void pushdown(int u)
{
	auto &root = tr[u]; auto &left = tr[u<<1]; auto &right = tr[u<<1|1]; 
	if(root.add)
	{
		left.add+=root.add; left.sum+=(ll)(left.r-left.l+1)*root.add;
		right.add+=root.add; right.sum+=(ll)(right.r-right.l+1)*root.add;
		root.add=0;
	}
}
void build(int u,int l,int r)
{
	if(l==r) tr[u]={l,r,w[r],0};
	else 
	{	tr[u].l=l;tr[u].r=r;
		int mid = l+r>>1;
		build(u<<1,l,mid); build(u<<1|1,mid+1,r);
		pushup(u);
	}	
} 

void modify(int u,int l,int r,int d)
{
	if(tr[u].l>=l&&tr[u].r<=r) 
	{
		tr[u].sum+=(ll)(tr[u].r-tr[u].l+1)*d;
		tr[u].add+=d;
	}
	else 
	{
		pushdown(u);
		int mid = tr[u].l+tr[u].r>>1;
		if(l<=mid) modify( u<<1, l, r, d);
		if(r>mid) modify( u<<1|1,l, r, d);
		pushup(u);
	}
}



ll query(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
	pushdown(u);	
	int mid=tr[u].l + tr[u].r>>1; 
	ll sum=0;
	if(mid>=l)  sum=query(u<<1,l,r);
	if(r>mid)  sum+=query(u<<1|1,l,r);
	return sum;
	
}


int main() 
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>w[i];	
	build(1,1,n);
	while(m--)
	{
		char op[2];
		int l,r;
		scanf("%s%d%d",op,&l,&r);
		if(*op=='C')
		{
			int d;
			cin>>d;
			modify(1,l,r,d);
		}
		else
		{	
			cout<<query(1,l,r)<<endl;
		}
	}
	return 0;
}

3.Splay

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5+10;
int n,m;
const int inf=0x3f3f3f3f;
struct node{
	int s[2],p,v;
	int rev,same;//rev反转,相同
	int size,sum,ms,ls,rs;
	void init(int _v,int _p)
	{
		s[0]=s[1]=0;
		p=_p,v=_v;
		rev=same=0;
		size=1;
		sum=ms=v;
		ls=rs=max(v,0);
	 } 
}tr[N];
int root,nodes[N],tt;
int w[N];

void pushup(int x)
{
    auto &u = tr[x], &l = tr[u.s[0]], &r = tr[u.s[1]];
    u.size = l.size + r.size + 1;
    u.sum = l.sum + r.sum + u.v;
    u.ls = max(l.ls, l.sum + u.v + r.ls);
    u.rs = max(r.rs, r.sum + u.v + l.rs);
    u.ms = max(max(l.ms, r.ms), l.rs + u.v + r.ls);
}

void pushdown(int x)
{
    auto &u = tr[x], &l = tr[u.s[0]], &r = tr[u.s[1]];
    if (u.same)
    {
        u.same = u.rev = 0;
        if (u.s[0]) l.same = 1, l.v = u.v, l.sum = l.v * l.size;
        if (u.s[1]) r.same = 1, r.v = u.v, r.sum = r.v * r.size;
        if (u.v > 0)
        {
            if (u.s[0]) l.ms = l.ls = l.rs = l.sum;
            if (u.s[1]) r.ms = r.ls = r.rs = r.sum;
        }
        else
        {
            if (u.s[0]) l.ms = l.v, l.ls = l.rs = 0;
            if (u.s[1]) r.ms = r.v, r.ls = r.rs = 0;
        }
    }
    else if (u.rev)
    {
        u.rev = 0, l.rev ^= 1, r.rev ^= 1;
        swap(l.ls, l.rs), swap(r.ls, r.rs);
        swap(l.s[0], l.s[1]), swap(r.s[0], r.s[1]);
    }
}


void rotate(int x)
{
    int y = tr[x].p, z = tr[y].p;
    int k = tr[y].s[1] == x;  // k=0表示x是y的左儿子;k=1表示x是y的右儿子
    tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;
    tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
    tr[x].s[k ^ 1] = y, tr[y].p = x;
    pushup(y), pushup(x);
}

void splay(int x, int k)
{
    while (tr[x].p != k)
    {
        int y = tr[x].p, z = tr[y].p;
        if (z != k)
            if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y)) rotate(x);
            else rotate(y);
        rotate(x);
    }
    if (!k) root = x;
}

void insert(int v)
{
    int u = root, p = 0;
    while (u) p = u, u = tr[u].s[v > tr[u].v];
    u = ++ idx;
    if (p) tr[p].s[v > tr[p].v] = u;
    tr[u].init(v, p);
    splay(u, 0);
}

int get_k(int k)
{
    int u = root;
    while (true)
    {
        pushdown(u);
        if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0];
        else if (tr[tr[u].s[0]].size + 1 == k) return u;
        else k -= tr[tr[u].s[0]].size + 1, u = tr[u].s[1];
    }
    //return -1;
}

int build(int l,int r,int p)
{
	int mid=l+r>>1;
	int u=nodes[tt--];
	tr[u].init(w[mid],p);
	if(l<mid) tr[u].s[0]=build(l,mid-1,u);
	if(r>mid) tr[u].s[1]=build(mid+1,r,u);
	pushup(u);
	return u;
}

void dfs(int u)
{
	if(tr[u].s[0]) dfs(tr[u].s[0]);
	if(tr[u].s[1]) dfs(tr[u].s[1]);
	nodes[++tt]=u;
}
int main()
{
	for(int i=1;i<N;i++) nodes[++tt]=i; 
	scanf("%d%d",&n,&m);
	tr[0].ms=w[n+1]=w[0]=-inf;
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	root=build(0,n+1,0); 
	char op[20];
	while(m--)
	{
		scanf("%s",op);
		if(!strcmp(op,"INSERT"))
		{
			int posi,tot;
			scanf("%d%d",&posi,&tot);
			for(int i=0;i<tot;i++) scanf("%d",&w[i]);
			int l=get_k(posi+1),r=get_k(posi+2);
			splay(l,0);
			splay(r,l);
			int u=build(0,tot-1,r);
			tr[r].s[0]=u;
			pushup(r),pushup(l);
		}
		else if(!strcmp(op,"DELETE"))
		{
			int posi,tot;
			scanf("%d%d",&posi,&tot);
			int l=get_k(posi),r=get_k(posi+tot+1);
			splay(l,0);
			splay(r,l);
			dfs(tr[r].s[0]);
			tr[r].s[0]=0;
			pushup(r),pushup(l);
		}
		else if(!strcmp(op,"MAKE-SAME"))
		{
			int posi,tot,c;
			scanf("%d%d%d",&posi,&tot,&c);
			int l=get_k(posi),r=get_k(posi+tot+1);
			splay(l,0);
			splay(r,l);
			auto &son=tr[tr[r].s[0]];
			son.same=1,son.v=c,son.sum=son.size*c;
			if(c>0) son.ms=son.ls=son.rs=son.sum;
            else son.ms=c, son.ls=son.rs=0;
            pushup(r), pushup(l);
		}
		else if(!strcmp(op,"REVERSE"))
		{
			int posi,tot;
			scanf("%d%d",&posi,&tot);
			int l=get_k(posi),r=get_k(posi+tot+1);
			splay(l,0);
			splay(r,l);
			auto &son=tr[tr[r].s[0]];
			son.rev^=1;
			swap(son.ls,son.rs);
			swap(son.s[0],son.s[1]);
			pushup(r),pushup(l);
		}
		else if(!strcmp(op,"GET-SUM"))
		{
			int posi,tot;
			scanf("%d%d",&posi,&tot);
			int l=get_k(posi),r=get_k(posi+tot+1);
			splay(l,0);
			splay(r,l);
			printf("%d\n",tr[tr[r].s[0]].sum);
		}
		else printf("%d\n",tr[root].ms);
	}
}

4.树套树

线段树套平衡树

#include<bits/stdc++.h>

using namespace std;
typedef long long ll; 
const int inf=0x3f3f3f3f; 
const int N = 5e4+10;
int a[N];
int L[N],R[N],T[N],idx;
int n,m;
struct node{
	int s[2],p,v;
	int size;
	void init(int _v,int _p)
	{
		v=_v,p=_p;
		size=1;
	}
}tr[N*40];

void pushup(int u)
{
	tr[u].size=tr[tr[u].s[0]].size+tr[tr[u].s[1]].size+1; 
}

void rotate(int x)
{
    int y = tr[x].p, z = tr[y].p;
    int k = tr[y].s[1] == x;  // k=0表示x是y的左儿子;k=1表示x是y的右儿子
    tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;
    tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
    tr[x].s[k ^ 1] = y, tr[y].p = x;
    pushup(y), pushup(x);
}

void splay(int &root,int x, int k)
{
    while (tr[x].p != k)
    {
        int y = tr[x].p, z = tr[y].p;
        if (z != k)
            if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y)) rotate(x);
            else rotate(y);
        rotate(x);
    }
    if (!k) root = x;
}


void insert(int &root ,int v)
{
	int u = root, p = 0;
    while (u) p = u, u = tr[u].s[v > tr[u].v];
    u = ++ idx;
    if (p) tr[p].s[v > tr[p].v] = u;
    tr[u].init(v, p);
    splay(root,u, 0);
}

 void build(int u,int l,int r)
 {
 	L[u]=l;R[u]=r;
 	insert(T[u],-inf),insert(T[u],inf);
 	for(int i=l;i<=r;i++)
 	{
 		insert(T[u],a[i]);
 	}
 	if(l==r) return ;
 	int mid=l+r>>1;
 	build(u<<1,l,mid);
 	build(u<<1|1,mid+1,r);
 }


int update(int &root,int x,int y)
{
	int u=root;
	while(u)
	{
		if(tr[u].v==x) break;
		if(tr[u].v<x) u=tr[u].s[1];
		else u=tr[u].s[0];
	 } 
	 splay(root,u,0);
	 int l=tr[u].s[0],r=tr[u].s[1];
	 splay(root,u,0);
	 while(tr[l].s[1]) l=tr[u].s[1];
	 while(tr[r].s[0]) r=tr[u].s[0];
	 splay(root,l,0);
	 splay(root,r,l);
	 tr[l].s[0]=0;
	 pushup(r),pushup(l);
	 insert(root,y);
}

int get_k(int root,int v)
{
    int u = root,res=0;
    while (u)
    {
        if (tr[u].v<v) res+=tr[tr[u].s[0]].size+1,u=tr[u].s[1];
        else u=tr[u].s[0];
    }
    return res;
}

int get_pre(int root,int x)
{
	int u=root,res=-inf;
	while(u)
	{
		if(tr[u].v<x) res=max(res,tr[u].v),u=tr[u].s[1];
		else u=tr[u].s[0];
	}
	return res;
}

int get_suf(int root,int x)
{
	int u=root,res=inf;
	while(u)
	{
		if(tr[u].v>x) res=min(res,tr[u].v),u=tr[u].s[0];
		else u=tr[u].s[1];
	 } 
	 return res;
}
int query(int u,int l,int r,int x)
{
	if(l<=L[u]&&R[u]<=r) return get_k(T[u],x)-1;
	else {
		int mid=L[u]+R[u]>>1;
		int res=0;
		if(l<=mid) res+=query(u<<1,l,r,x);
		if(r>mid) res+=query(u<<1|1,l,r,x);
		return res;
	}

}

void change(int u,int pos,int x)
{
	update(T[u],a[pos],x);
	if(L[u]==R[u]) return;
	int mid=L[u]+R[u]>>1;
	if(pos<=mid) change(u<<1,pos,x);
	if(pos>mid) change(u<<1|1,pos,x);
}

int query_pre(int u,int l,int r,int x)
{
	if(l<=L[u]&&R[u]<=r) return get_pre(T[u],x);
	int mid=L[u]+R[u]>>1,res=-inf;
	if(l<=mid) res=max(res,query(u<<1,l,r,x));
	if(r>mid) res=max(res,query(u<<1|1,l,r,x));
} 

int query_suf(int u,int l,int r,int x)
{
	if(l<=L[u]&&R[u]<=r) return get_suf(T[u],x);
	int mid=L[u]+R[u]>>1,res=inf;
	if(l<=mid) res=min(res,query_suf(u<<1,l,r,x));
	if(r>mid) res=min(res,query_suf(u<<1|1,l,r,x));
} 

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)	cin>>a[i];
	build(1,1,n);
	while(m--)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int l,r,x;
			cin>>l>>r>>x;
			cout<<query(1,l,r,x)+1<<endl;
		}
		else if(op==2)
		{
			int l,r,x;
			cin>>l>>r>>x;
			int a=0,b=1e8;
			while(l<r)
			{
				int mid=a+b+1>>1;
				if(query(1,l,r,mid)+1<=x) a=mid;
				else b=mid-1;
			}
			cout<<b<<endl;
		}
 		else if(op==3)
 		{
 			int pos,x;
 			cin>>pos>>x;
 			change(1,pos,x);
 			a[pos]=x;
 		}
 		else if(op==4)
 		{
 			int l,r,x;
 			cin>>l>>r>>x;
 			cout<<query_pre(1,l,r,x);
 	 	}
 		 else {
 		 	int l,r,x;
 		 	cin>>l>>r>>x;
 		 	cout<<query_suf(1,l,r,x);
 		} 
		 
 	}
	
}

5.主席树

区间k-th

#include<bits/stdc++.h>

using namespace std;

vector<int> ve;

int getid(int x){return lower_bound(ve.begin(),ve.end(),x)-ve.begin()+1;}

const int N=1e5+10;

int a[N];
struct node{
    int l,r;
    int sum;
}tr[N*40];
int cnt, root[N];

void insert(int l,int r,int pre,int &now,int x)
{
    tr[++cnt]=tr[pre];
    now=cnt;
    tr[now].sum++;
    if(l==r)    return ;
    int mid=(l+r)>>1;
    if(x<=mid)  insert(l,mid,tr[pre].l,tr[now].l,x);
    else insert(mid+1,r,tr[pre].r,tr[now].r,x);    
}

int query(int l,int r,int L,int R,int k)
{
    if(l==r) return l;
    int mid=l+r>>1;
    int temp=tr[tr[R].l].sum-tr[tr[L].l].sum;
    if(k<=temp)
    {
        query(l,mid,tr[L].l,tr[R].l,k);
    }
    else query(mid+1,r,tr[L].r,tr[R].r,k-temp);
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)   cin>>a[i],ve.push_back(a[i]);
    sort(ve.begin(),ve.end());
    ve.erase(unique(ve.begin(),ve.end()),ve.end());
    for(int i=1;i<=n;i++)
    {
        insert(1,n,root[i-1],root[i],getid(a[i]));
    }
    while(m--)
    {
        int l,r,k;
        cin>>l>>r>>k;
        cout<<ve[query(1,n,root[l-1],root[r],k)-1]<<endl;
    }
}

区间前k大和

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int rt[N],idx;
ll pre[N];
int a[N];
vector<int> num;
struct node{
    int l,r;
    int cnt;
    ll sum;
    ll d;
}tr[N*40];
int n;
void init(){
    pre[1]=1;
    for(ll i=2;i<=100005;i++)
        pre[i]=pre[i-1]+i*i;
}
void build(int &p,int l,int r){
    p=++idx;
    if(l==r){
        return ;
    }
    int mid=l+r>>1;
    build(tr[p].l,l,mid);
    build(tr[p].r,mid+1,r);
}
int find(int x){
    return lower_bound(num.begin(),num.end(),x)-num.begin()+1;
}
void insert(int &p,int q,int l,int r,int pos,int cnt){
    p=++idx,tr[p]=tr[q];
    tr[p].cnt+=1,tr[p].sum+=cnt;
    if(l==r){
        tr[p].d=cnt;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        insert(tr[p].l,tr[q].l,l,mid,pos,cnt);
    else
        insert(tr[p].r,tr[q].r,mid+1,r,pos,cnt);
}
ll query(int p,int q,int l,int r,int k){
    if(l==r){
        return tr[p].d*k;
    }
    int cnt=tr[tr[p].r].cnt-tr[tr[q].r].cnt;
    int mid=l+r>>1;
    if(k<=cnt){
        return query(tr[p].r,tr[q].r,mid+1,r,k);
    }
    else{
        return  tr[tr[p].r].sum-tr[tr[q].r].sum+query(tr[p].l,tr[q].l,l,mid,k-cnt);
    }
}
int main(){
    //ios::sync_with_stdio(false);
    int t;
    cin>>t;
    init();
    while(t--){
        cin>>n;
        int i;
        idx=0;
        num.clear();
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            num.push_back(a[i]);
            rt[i]=0;
        }
        build(rt[0],1,n);
        sort(num.begin(),num.end());
        num.erase(unique(num.begin(),num.end()),num.end());
        for(i=1;i<=n;i++){
            insert(rt[i],rt[i-1],1,n,find(a[i]),a[i]);
        }
        int l,r,k;
        int q;
        cin>>q;
        while(q--){
            scanf("%d%d%d",&l,&r,&k);
            printf("%lld\n",pre[(r-l+1)]+query(rt[r],rt[l-1],1,n,k));
        }
    }
}

6.树状数组

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
ll a[N],minv[N],maxv[N],tr[N<<1],n;
ll lowbit(int x)
{
	return x&-x;
}
void modify(int x,int c)//修改树状数组x位置的值
{
	for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
ll query(int x)//查询区间1~x的区间和;
{
	ll res=0;
	for(int i=x;i>=1;i-=lowbit(i)) res+=tr[i];
	return res; 
}

7.笛卡尔树

#include<bits/stdc++.h>
#define ll long long
#define dl double
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
#define println(x){printf(":\n");for (int tmpi=1;tmpi<=n;tmpi++)printf("%d ",x[i]);printf("\n");}
using namespace std;

const int N=1e5+7;
const int INF=0x3f3f3f3f;
const int M=1e9+7;

struct Node {
    int index, val;    // index表示原数组的索引,val为当前节点的键值
    Node *parent, *lefts, *rights;    // 这三个指针分别指向父节点,左子节点,右子节点
    Node(int id = 0, int v = 0, Node *l = NULL, Node *r = NULL) { index = id; val = v; lefts = l; rights = r; }
};

Node * build(int arr[], int fa[], int size) {    // 这里构建一个根节点为最小值的笛卡尔树
    std::stack<Node * > S;    // 存储最右边路径的栈
    Node *now, *next, *last;
    for (int i = 1; i <= size; i++) {
        next = new Node(i, arr[i]); last = NULL;    // last用来指向最后被弹出栈的元素(若有弹出),它的作用后面会写到
        while (!S.empty()) {
            if (S.top()->val < next->val) {    // 若栈顶节点的键值比当前节点键值小了,那么当前节点就做栈顶节点的右子节点
                now = S.top();
                if (now->rights) {    // 而栈顶节点的原右子节点要变成当前节点的左子节点(由于前面一定与当前节点比较过了,栈顶节点右子树的键值一定都比当前节点大)
                    now->rights->parent = next;
                    next->lefts = now->rights;
                    fa[now->rights->index]=next->index;
                }
                now->rights = next;
                next->parent = now;
                fa[next->index]=now->index;
                break;
            }
            last = S.top();
            S.pop();
        }
        if (S.empty() && last) {    // 这里为了特判一种可能出现的情况,就是当前节点把栈全部弹空了,就要把原先的根节点作为当前节点的左子节点
            next->lefts = last;
            last->parent = next;
            fa[last->index]=next->index;
        }
        S.push(next);
    }
    while (!S.empty()) now = S.top(), S.pop();
    
	return now;
}; 

//void dfs(Node* root){
//	fa[root->lefts->index]=root->index;
//	fa[root->rights->index]=root->index;
//	lc[root->index]=root->lefts->index;
//	rc[root->index]=root->rights->index;
//	if (root->lefts) dfs(root->lefts);
//	if (root->rights) dfs(root->rights);
//	return;
//}

int n;
int a[N];
int fa[N];

void solve(){
	read(n);
	fo(i,1,n) read(a[i]);
//	dfs(build(a,n));
	build(a,fa,n);
	fo(i,1,n) printf("%d ",fa[i]); 
}

int main(){
//	int T;
//	scanf("%d",&T);
//	for (int i=1;i<=T;i++)
	solve();
	return 0;
}

 

8.dsu on tree

#include<bits/stdc++.h>
#define fp(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
typedef double dl;
using namespace std;

const int N=2e5+7;
const int M=2*N;
const int INF=0x3f3f3f3f;
int e[M],w[M],ne[M],h[N],idx;
ll sz[N],top[N],fa[N],son[N],ans[N],col[N],cnt[N];
ll n,m,Son=0,mx=0,sum=0;

void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
} 

void add(int u,int fa,int val)
{
	cnt[col[u]]+=val;
	if(cnt[col[u]]>mx) sum=col[u],mx=cnt[col[u]];
	else if(cnt[col[u]]==mx)
	{
		sum+=col[u];
	}
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa||j==Son) continue;
		add(j,u,val);
	}
}

void dfs1(int u,int father)
{
	sz[u]=1;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==father) continue;
		dfs1(j,u);
		sz[u]+=sz[j];
		if(sz[son[u]]<sz[j]) son[u]=j;
	}
}

void dfs2(int u,int fa,int op)
{
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa||j==son[u]) continue;
		dfs2(j,u,0);
	}
	if(son[u]) dfs2(son[u],u,1) ,Son=son[u];
	add(u,fa,1);
	Son=0;
	ans[u]=sum;
	if(!op) add(u,fa,-1) ,sum=0,mx=0;
}
void solve()
{
	memset(h,-1,sizeof(h));
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&col[i]);
	m=n-1;
	while(m--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);
		add(b,a);
	}
	dfs1(1,0);
	dfs2(1,0,0);
	for(int i=1;i<=n;i++)
	{
		printf("%lld ",ans[i]);
	}
	
}


三.字符串

1.KMP

1.KMP

#include <iostream>

using namespace std;

const int N = 10010, M = 100010;

int n, m;
int ne[N];
char s[M], p[N];

int main()
{
    cin >> n >> p + 1 >> m >> s + 1;

    for (int i = 2, j = 0; i <= n; i ++ )
    {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j ++ ;
        ne[i] = j;
    }

    for (int i = 1, j = 0; i <= m; i ++ )
    {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j ++ ;
        if (j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }

    return 0;
}

2.EXKMP

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

const int N=2e6+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;


char S[N], T[N];
int slen, tlen;
int nxt[N];
int ext[N]; 

void get_next()
{
    int i = 0, j, po;
    nxt[0] = tlen;
    while (T[i] == T[i + 1] && i + 1 < tlen)
        i++;
    nxt[1] = i;
    po = 1;
    for (i = 2; i < tlen; i++)
    {
        if (nxt[i - po] + i < nxt[po] + po)
            nxt[i] = nxt[i - po];
        else
        {
            j = nxt[po] + po - i;
            if (j < 0)j = 0;
            while (i + j < tlen && T[j] == T[j + i])
                j++;
            nxt[i] = j;
            po = i;
        }
    }
}

void EXKMP()
{
    int i = 0, j, po, slen = strlen(S), tlen = strlen(T);
    get_next();//计算子串的nxt数组
    while(S[i] == T[i] && i < tlen && i < slen) //计算ext[0]
        i++;
    ext[0] = i;
    po = 0; //初始化po的位置
    for(i = 1; i < slen; i++)
    {
        if(nxt[i - po] + i < ext[po] + po) //第一种情况,直接可以得到ext[i]的值
            ext[i] = nxt[i - po];
        else//第二种情况,要继续匹配才能得到ext[i]的值
        {
            j = ext[po] + po - i;
            if(j < 0)j = 0; //如果i>ext[po]+po则要从头开始匹配
            while(i + j < slen && j < tlen && S[j + i] == T[j]) //计算ext[i]
                j++;
            ext[i] = j;
            po = i; //更新po的位置
        }
    }
}

//#include<local.h>
//using namespace Debug;

void solve()
{
    cin >> S >> T;
    slen = strlen(S);
    tlen = strlen(T);
    EXKMP();
//    println(nxt,nxt+tlen,"nxt");
//    println(ext+0,ext+slen,"ext");
	ll ans = 0;
	fo(i, 0, slen - 1){
		if (S[i + ext[i]] < T[ext[i]]) ans+=slen-i-ext[i];
		ans+=min(tlen-1,ext[i]);
	}
	cout << ans;
}

int main(){
//	int T;read(T);
//	for(int i=1;i<=T;i++)
		solve();
}

2.AC自动机

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 6;
int n;

namespace AC {
int tr[N][26], tot;
int e[N], fail[N];
void insert(char *s) {
  int u = 0;
  for (int i = 1; s[i]; i++) {
    if (!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++tot;
    u = tr[u][s[i] - 'a'];
  }
  e[u]++;
}
queue<int> q;
void build() {
  for (int i = 0; i < 26; i++)
    if (tr[0][i]) q.push(tr[0][i]);
  while (q.size()) {
    int u = q.front();
    q.pop();
    for (int i = 0; i < 26; i++) {
      if (tr[u][i])
        fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);
      else
        tr[u][i] = tr[fail[u]][i];
    }
  }
}
int query(char *t) {
  int u = 0, res = 0;
  for (int i = 1; t[i]; i++) {
    u = tr[u][t[i] - 'a'];  // 转移
    for (int j = u; j && e[j] != -1; j = fail[j]) {
      res += e[j], e[j] = -1;
    }
  }
  return res;
}
}  // namespace AC

char s[N];
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%s", s + 1), AC::insert(s);
  scanf("%s", s + 1);
  AC::build();
  printf("%d", AC::query(s));
  return 0;
}

3.马拉车

#include<bits/stdc++.h>

using namespace std;

const int N = 3e5;

int len1,len2,p[N],ans;
char str[N],s[N];

void init()
{
	str[0]='$';//构建新的字符串,将无论奇偶都形成奇数长度的字符串 ; 
	str[1]='#';
	for(int i=0;i<len1;i++)
	{
		str[i*2+2]=s[i];
		str[i*2+3]='#';
	}
	len2=len1*2+2;
	str[len2]='*';
}

void manacher()
{
	int id=0,mx=0;
	for(int i=1;i<len2;i++)
	{
		if(mx>i) p[i]=min(p[2*id-i],mx-i); 
		else p[i]=1;
		for(;str[i+p[i]]==str[i-p[i]];p[i]++); //扩展长度; 
		if(p[i]+i>mx)
		{
			mx=p[i]+i;	
			id=i;
		}
	}
}

int main()
{
	while(scanf("%s",s)!=EOF)
	{
		len1=strlen(s);
		init();
		manacher(); 
		ans=0;
		for(int i=0;i<len2;i++)
		{
			ans=max(p[i],ans);
		}
		cout<<ans-1<<endl; 
	}
}

4.哈希

#include <iostream>
#include <algorithm>
using namespace std;

typedef unsigned long long ULL;
const int N = 100010, P = 131;

int n, m;
char str[N];
ULL h[N], p[N];

ULL get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
    scanf("%d%d", &n, &m);
    scanf("%s", str + 1);

    p[0] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        h[i] = h[i - 1] * P + str[i];
        p[i] = p[i - 1] * P;
    }

    while (m -- )
    {
        int l1, r1, l2, r2;
        scanf("%d%d%d%d", &l1, &r1, &l2, &r2);

        if (get(l1, r1) == get(l2, r2)) puts("Yes");
        else puts("No");
    }

    return 0;
}


5.双哈希

struct Hash
{
	ull h1[maxn],h2[maxn],p1[maxn],p2[maxn],P1 = 13331,P2 = 131,mod1 = 1e9+7,mod2 = 1e8+7;
	char s[maxn];int len;
	void init_pow(){
		p1[0] = 1,p2[0] = 1;
		h1[0] = 0,h2[0] = 0;
		for(int i = 1;i<=maxn;i++){
			p1[i] = p1[i-1]*P1%mod1;
			p2[i] = p2[i-1]*P2%mod2;
		}
	}
	void init_hs(){
	    len = strlen(s+1);
	    for(int i = 1;i<=len;i++){
	        h1[i] = (h1[i-1]*P1%mod1+(s[i]-'a'))%mod1;
	        h2[i] = (h2[i-1]*P2%mod2+(s[i]-'a'))%mod2;
	    }
	}
	pii geths(int l,int r){
		ull hs1 = (h1[r] - h1[l-1]*p1[r-l+1]%mod1 + mod1)%mod1;
		ull hs2 = (h2[r] - h2[l-1]*p2[r-l+1]%mod2 + mod2)%mod2;
		return {hs1,hs2};
	}
}H;

6.序列自动机

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5+20;

int dp[N][30];

char a[N],b[N];

int n,m; 
void build()
{
	memset(dp,-1,sizeof(dp));
	for(int j=n-1;j>=0;j--)
	{
		for(int i=0;i<26;i++)
		{
			if(a[j+1]-'a'==i)
			dp[j][i]=j+1;
			else dp[j][i]=dp[j+1][i];
		}
	}
}
int main()
{

	cin>>n>>m;
	cin>>a+1;
	build();
	while(m--)
	{
		cin>>b;
		bool flag=0;
		int j=0;
		int len=strlen(b);
		for(int i=0;i<len;i++)
		{
			if(dp[j][b[i]-'a']==-1)
			{
				flag=1;
				break;
			}
			j=dp[j][b[i]-'a'];
		}
		if(flag==1)
		cout<<"NO"<<endl;
		else cout<<"YES"<<endl; 
	}
	
}

7.SAM

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

const int maxp=26,maxn=2e5+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;

int n,m;

struct Suffix_Node{
	int trans[maxp],par,len;
	void Clear(){
		memset(trans,0,sizeof(trans));
		par=len=0;
	}
};

class Suffix_Automaton{
 private:
	Suffix_Node S[maxn];
	int p,np,size,crp;
 public:
 Suffix_Automaton():p(1),np(1),size(1),crp(1){};
	const void Clear(){
		for(int i=0;i<=size;++i) S[i].Clear();
		p=np=size=crp=1;
	}
	const int Match(const char ch)const{
		return S[crp].trans[ch-'a'];
	}
	const void Withdraw(const int len){
		while( crp!=0 && S[S[crp].par].len>=len ) crp=S[crp].par;
		if( crp==0 ) crp=1;
	}
	const void Transfer(const int len,const char ch){
		crp=S[crp].trans[ch-'a'];
		if( crp==0 ) crp=1;
		Withdraw(len);
	}
	const void Insert(const char ch){
		int x=ch-'a';
		np=++size;
		S[np].len=S[p].len+1;
		while( p!=0 && !S[p].trans[x] ) S[p].trans[x]=np,p=S[p].par;
		if( p==0 ) S[np].par=1;
		else{
			int q,nq;
			q=S[p].trans[x];
			if( S[q].len==S[p].len+1 ) S[np].par=q;
			else{
				nq=++size;
				S[nq]=S[q],S[nq].len=S[p].len+1;
				S[np].par=S[q].par=nq;
				while( p!=0 && S[p].trans[x]==q ) S[p].trans[x]=nq,p=S[p].par;
			}
		}
		p=np;
	}
}SAM;

void solve(){
	
}

int main(){
//	int T;read(T);
//	for(int i=1;i<=T;i++)
		solve();
}

8.回文树

struct PAM{ // 每个节点代表一个回文串
    int next[maxn][ALP]; // next指针,参照Trie树
    int fail[maxn]; // fail失配后缀链接
    int cnt[maxn]; // 此回文串出现个数
    int num[maxn];
    int len[maxn]; // 回文串长度
    int s[maxn]; // 存放添加的字符
    int last; //指向上一个字符所在的节点,方便下一次add
    int n; // 已添加字符个数
    int p; // 节点个数
 
    int newnode(int w){ // 初始化节点,w=长度
        for(int i=0;i<ALP;i++)
            next[p][i] = 0;
        cnt[p] = 0;
        num[p] = 0;
        len[p] = w;
        return p++;
    }
    void init(){
        p = 0;
        newnode(0);
        newnode(-1);
        last = 0;
        n = 0;
        s[n] = -1; // 开头放一个字符集中没有的字符,减少特判
        fail[0] = 1;
    }
    int get_fail(int x){ // 和KMP一样,失配后找一个尽量最长的
        while(s[n-len[x]-1] != s[n]) x = fail[x];
        return x;
    }
    void add(int c){
        c -= 'a';
        s[++n] = c;
        int cur = get_fail(last);
        if(!next[cur][c]){
            int now = newnode(len[cur]+2);
            fail[now] = next[get_fail(fail[cur])][c];
            next[cur][c] = now;
            num[now] = num[fail[now]] + 1;
        }
        last = next[cur][c];
        cnt[last]++;
    }
    void count(){
        // 最后统计一遍每个节点出现个数
        // 父亲累加儿子的cnt,类似SAM中parent树
        // 满足parent拓扑关系
        for(int i=p-1;i>=0;i--)
            cnt[fail[i]] += cnt[i];
    }
}pam;

9.莫队

四.图论

1.最短路

1.优化dijkstra

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 1e6 + 10;

int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});

    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second, distance = t.first;

        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    cout << dijkstra() << endl;

    return 0;
}

2.spfa

#include<bits/stdc++.h>

using namespace std;

const int N = 5210;

int w[N],ne[N],e[N],h[N];
int idx=0;
int cnt[N];
bool st[N];
int dist[N];
int n;
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}


bool spfa()
{
    memset(dist, 0, sizeof dist);
    memset(cnt, 0, sizeof cnt);
    memset(st, 0, sizeof st);
    queue <int> q;
    for(int i=1;i<=n;i++)
    {
        q.push(i);
        st[i]=1;
    }
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=0;
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return 1;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=1;
                }
            }
        }
    }
    return 0;
}

int main()
{
    int T;
	scanf("%d",&T);
	//std::ios::sync_with_stdio(false);
    while(T--)
    {
    	int m1,m2;
    	idx=0;
        memset(h,-1,sizeof(h));
        scanf("%d%d%d",&n,&m1,&m2);
        while(m1--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        while(m2--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,-c);
        }
        if(spfa()) puts("YES");
        else puts("NO");
    }
    return 0;
}

3.第K短路

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
typedef pair<int, PII> PIII;

const int N = 1010, M = 200010;

int n, m, S, T, K;
int h[N], rh[N], e[M], w[M], ne[M], idx;
int dist[N], cnt[N];
bool st[N];

void add(int h[], int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

void dijkstra()
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, T});

    memset(dist, 0x3f, sizeof dist);
    dist[T] = 0;

    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.y;
        if (st[ver]) continue;
        st[ver] = true;

        for (int i = rh[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }
}

int astar()
{
    priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
    heap.push({dist[S], {0, S}});

    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.y.y, distance = t.y.x;
        cnt[ver] ++ ;
        if (cnt[T] == K) return distance;

        for (int i = h[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if (cnt[j] < K)
                heap.push({distance + w[i] + dist[j], {distance + w[i], j}});
        }
    }

    return -1;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    memset(rh, -1, sizeof rh);

    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(h, a, b, c);
        add(rh, b, a, c);
    }
    scanf("%d%d%d", &S, &T, &K);
    if (S == T) K ++ ;

    dijkstra();
    printf("%d\n", astar());

    return 0;
}

4.最短路计数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = 400010, mod = 100003;

int n, m;
int h[N], e[M], ne[M], idx;
int dist[N], cnt[N];
int q[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void bfs()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    cnt[1] = 1;

    int hh = 0, tt = 0;
    q[0] = 1;

    while (hh <= tt)
    {
        int t = q[hh ++ ];

        for (int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + 1)
            {
                dist[j] = dist[t] + 1;
                cnt[j] = cnt[t];
                q[ ++ tt] = j;
            }
            else if (dist[j] == dist[t] + 1)
            {
                cnt[j] = (cnt[j] + cnt[t]) % mod;
            }
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);

    while (m -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }

    bfs();

    for (int i = 1; i <= n; i ++ ) printf("%d\n", cnt[i]);

    return 0;
}

2.SPFA求负环

#include<bits/stdc++.h>

using namespace std;

const int N = 5210;

int w[N],ne[N],e[N],h[N];
int idx=0;
int cnt[N];
bool st[N];
int dist[N];
int n;
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}


bool spfa()
{
    memset(dist, 0, sizeof dist);
    memset(cnt, 0, sizeof cnt);
    memset(st, 0, sizeof st);
    queue <int> q;
    for(int i=1;i<=n;i++)
    {
        q.push(i);
        st[i]=1;
    }
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=0;
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return 1;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=1;
                }
            }
        }
    }
    return 0;
}

int main()
{
    int T;
	scanf("%d",&T);
	//std::ios::sync_with_stdio(false);
    while(T--)
    {
    	int m1,m2;
    	idx=0;
        memset(h,-1,sizeof(h));
        scanf("%d%d%d",&n,&m1,&m2);
        while(m1--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        while(m2--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,-c);
        }
        if(spfa()) puts("YES");
        else puts("NO");
    }
    return 0;
}

3.差分约束

求一组如 x i ≤ y i + c x_i \leq y_i+c xiyi+c 的不等式组的可行解

从源点出发可以遍历到所有的边,才能满足所有条件

令差值最大

$x_i \leq y_i+c $

add(j,i,c);

求最短路,有负环无解

令差值最小

$x_i \geq y_i+c $

add(j,i,c);

求最长路,有正环无解

4.树链刨分

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5+20;
const int M = 2*N;
int e[M],w[M],ne[M],h[N],idx;
int id[N],nw[N],cnt=0;
int dep[N],sz[N],top[N],fa[N],son[N];


void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

struct node{
	int l,r;
	ll add,sum;
}tr[N<<2];

void dfs1(int u, int father, int depth)
{
    dep[u] = depth, fa[u] = father, sz[u] = 1;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == father) continue;
        dfs1(j, u, depth + 1);
        sz[u] += sz[j];
        if (sz[son[u]] < sz[j]) son[u] = j;
    }
}

void dfs2(int u, int t)
{
    id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;
    if (!son[u]) return;
    dfs2(son[u], t);
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa[u] || j == son[u]) continue;
        dfs2(j, j);
    }
}

void pushup(int u)
{
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}

void pushdown(int u)
{
	auto &root =tr[u],&left =tr[u<<1],&right=tr[u<<1|1];
	if(root.add)
	{
		left.add+=root.add,right.add+=root.add;
		left.sum+=(left.r-left.l+1)*root.add;
		right.sum+=(right.r-right.l+1)*root.add;
		root.add=0;
	}
}

void build(int u,int l,int r)
{
	if(l==r)
	{
		tr[u]={l,r,0,nw[l]};
		return ;
	}
	tr[u]={l,r,0};
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}

void update(int u,int l,int r,int k)
{
	if(l<=tr[u].l&&tr[u].r<=r)
	{
		tr[u].add+=k;
		tr[u].sum+=(tr[u].r-tr[u].l+1)*k;
		return ;
	}
	else 
	{
		pushdown(u);
		int mid=tr[u].l+tr[u].r>>1;
		if(l<=mid) update(u<<1,l,r,k);
		if(r>mid) update(u<<1|1,l,r,k);
		pushup(u);
	}
}

ll query(int u,int l,int r)
{
	if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
	else {
		pushdown(u);
		int mid=tr[u].l+tr[u].r>>1;
		ll res=0;
		if(l<=mid) res+=query(u<<1,l,r);
		if(r>mid) res+=query(u<<1|1,l,r);
		return res;
	}
}

void update_path(int u,int v,int k)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		update(1,id[top[u]],id[u],k);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v]) swap(u,v);
	update(1,id[v],id[u],k);
}

ll query_path(int u,int v)
{
	ll res=0;
	while(top[u]!=top[v])
	{

		if(dep[top[u]]<dep[top[v]])	swap(u,v);
		res+=query(1,id[top[u]],id[u]);
		u=fa[top[u]];
	}

		if(dep[u]<dep[v]) swap(u,v);
		res+=query(1,id[v],id[u]);
		return res;
	
}

void update_tree(int u,int k)
{
	update(1,id[u],id[u]+sz[u]-1,k);
}

ll query_tree(int u)
{
	return query(1,id[u],id[u]+sz[u]-1);
}
int main()
{
	int n,m;
	scanf("%d",&n);
	memset(h,-1,sizeof(h));
	
	for(int i=1;i<=n-1;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n;i++)	scanf("%d",&w[i]);
	dfs1(1,-1,1);
	dfs2(1,1);
	build(1,1,n);
	scanf("%d",&m);
	while(m--)
	{
		int op,u,v,k;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d%d",&u,&v,&k);
			update_path(u,v,k);
		}
		if(op==2)
		{
			scanf("%d%d",&u,&k);
			update_tree(u,k);
		}
		if(op==3)
		{
			scanf("%d%d",&u,&v);
			printf("%lld\n",query_path(u,v));
		}
		if(op==4)
		{
			scanf("%d",&u);
			printf("%lld\n",query_tree(u));
		}
		
	}
	
} 

5.倍增lca

#include<bits/stdc++.h>

using namespace std;

const int N = 4E4+10;
const int M = 2*N;

int h[N],ne[M],e[M],idx;
int depth[N];
int fa[N][30];
queue<int> q;

void add(int a, int b )
{
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}

void bfs(int root)
{
	memset(depth,0x3f,sizeof(depth));
	depth[0]=0;depth[root]=1;
	q.push(root);
	while(q.size()!=0)
	{
		int t=q.front();
		q.pop();
		for(int i=h[t];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(depth[j]>depth[t]+1) 
			{
				depth[j]=depth[t]+1;
				q.push(j);
				fa[j][0]=t;
				for(int k=1;k<=15;k++)
				{
					fa[j][k]=fa[fa[j][k-1]][k-1];
				}
			}
		}
	}
}

int lca(int a,int b)
{
	if(depth[a]<depth[b]) swap(a,b);
	for(int k=15;k>=0;k--)
	{
		if(depth[fa[a][k]]>=depth[b])
		{
			a=fa[a][k];
		}
	}
	if(a==b) return a;
	for(int k=15;k>=0;k--)
	{
		if(fa[a][k]!=fa[b][k])
		{
			a=fa[a][k];
			b=fa[b][k];
		}
	}
	return fa[a][0];	
	
}

int main()
{
	int t,m ;
	memset(h,-1,sizeof(h));
	cin>>t;
	int root=0;
	for(int i=1;i<=t;i++)
	{	
		int a,b;
		cin>>a>>b;
		if(b==-1)
		root=a;
		else 
		{
			add(a,b);
			add(b,a);
		} 
	}


	bfs(root);
	scanf("%d", &m);
    while (m -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        int p = lca(a, b);
        if (p == a) puts("1");
        else if (p == b) puts("2");
        else puts("0");
    }
} 

6.拓扑排序

#include<bits/stdc++.h>

using namespace std;

const int N=1E5+10;
const int M=1e5+10;

int ne[N],e[N],h[N],idx;
int d[N];
int n,m;

vector <int> ans;

void add(int a,int b)
{
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}

void top_sort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0)
        {
            q.push(i);
        }
    }
   while(q.size()!=0)
   {
       auto t=q.front();
       q.pop();
       ans.push_back(t);
       for(int i=h[t];i!=-1;i=ne[i])
        {
             int j=ne[i];
             d[j]--;
             if(d[j]==0) q.push(j);
        }
   }
   if(ans.size()==n)
   {
       for(auto x:ans) printf("%d ", x);
   }
   else cout<<"-1";
}

int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }
    top_sort();
    
}

7.最小生成树

1.kruskal

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
int f[maxn];
struct node {
	int u;int v;int w;
}edges[maxn];

bool cmp(node a,node b){
   return  a.w<b.w;
 }
 
int find(int x)
{
	if(f[x]!=x)
	f[x]=find(f[x]);
	return f[x];
}

void join(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x!=y)
	f[x]=y;
}

int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	f[i]=i;
	for(int i=0;i<m;i++)
	{
	  cin>>edges[i].u>>edges[i].v>>edges[i].w;
	}
	sort(edges,edges+m,cmp);
	int res=0,cnt=0;
	for(int i=0;i<m;i++)
	{
		int a=edges[i].u;int b=edges[i].v;int w=edges[i].w;
		a=find(a),b=find(b);
		if(a!=b)
		{
		join(a,b);
		res+=w;	
		cnt++;
	    }
	}
	if(cnt < n-1) cout<<"impossible";
	else cout<<res;
}

2.prime

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510, INF = 0x3f3f3f3f;

int n, m;
int g[N][N];
int dist[N];
bool st[N];


int prim()
{
    memset(dist, 0x3f, sizeof dist);

    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        if (i && dist[t] == INF) return INF;

        if (i) res += dist[t];
        st[t] = true;

        for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
    }

    return res;
}


int main()
{
    scanf("%d%d", &n, &m);

    memset(g, 0x3f, sizeof g);

    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        g[a][b] = g[b][a] = min(g[a][b], c);
    }

    int t = prim();

    if (t == INF) puts("impossible");
    else printf("%d\n", t);

    return 0;
}

3.次小生成树

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=510,M=10010;
int n,m,idx=0;
struct node {
	int a,b,w;
	bool f;
}edge[M];
int f[N];
int dist1[N][N],dist2[N][N];
int h[N], e[N * 2], w[N * 2], ne[N * 2];
bool cmp(node a,node b)
{
	return a.w<b.w;
}

int find(int x)
{
	return f[x]!=x?f[x]=find(f[x]):x;
}
void join(int x,int y)
{
	x=find(x); y = find(y);
	if(x!=y)
	f[x]=y; 
}
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}

void dfs(int u,int fa,int maxd1,int maxd2,int d1[],int d2[])
{
	d1[u]=maxd1,d2[u]=maxd2;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
		if(j!=fa)
		{
			int td1=maxd1,td2=maxd2;
			if(w[i]>td1) td2=td1 , td1=w[i];
			else if(w[i]>td2) td2=w[i];
			dfs(j,u,td1,td2,d1,d2);
		}
	}
}
int main(){
    int n,m;
	cin>>n>>m;
	memset(h,-1,sizeof(h));
	for(int i=0;i<m;i++)
	{
	  cin>>edge[i].a>>edge[i].b>>edge[i].w;	
	}
	
	for(int i=1;i<=n;i++)
 	f[i]=i;
 	for(int i=1;i<=n;i++)
 	find(i);
		
	sort(edge,edge+m,cmp);
	LL sum=0;
	for(int i=0;i<m;i++)
	{
		int a=edge[i].a; int b=edge[i].b; int w=edge[i].w;
		int pa=find(a), pb=find(b);
		if(pa!=pb)
		{
			sum+=w;
			join(edge[i].a,edge[i].b);
			add(a,b,w); add(b,a,w);
			edge[i].f=1;
		}
	}
	for(int i=1;i<=n;i++)
	dfs(i,-1,0,0,dist1[i],dist2[i]);
	
	LL res=1e18;
	for(int i=0;i<m;i++)
	{
		if(!edge[i].f)
		{
			int a=edge[i].a,b=edge[i].b,w=edge[i].w;
			LL t;
			if(w>dist1[a][b])
				t=sum+w-dist1[a][b];
			
			else if(w>dist2[a][b])
			    t=sum+w-dist2[a][b];
			    res=min(res,t);
		}
	}
	cout<<res<<endl;
	return 0;
} 

8.网络流

1.dinic

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int INF=0x3f3f3f3f;
const int N=10001;
const int maxn=10001;

class edge{
public:
	int to,flow,cap;
};

class network_flow{
public:
	int n;
	int s,t;
	int vis[maxn];
	int d[maxn];
	int cur[maxn];
	vector<int> G[maxn];
	vector<edge> edges;
	
	void init(int n){
		this->n=n;
		edges.clear();
		for (int i=0;i<=n;i++){
			G[i].clear();
		}
	}
	
	void addedge(int from,int to,int cap){
		edges.push_back((edge){to,0,cap});
		G[from].push_back(edges.size()-1);
		edges.push_back((edge){from,0,0});
		G[to].push_back(edges.size()-1);
//		printf("%d %d %d\n-",from,to,cap);
	}
	
	bool bfs(){
		memset(vis,0,sizeof(vis));
		queue<int> q;
		q.push(s);
		d[s]=0;
		vis[s]=1;
		while(!q.empty()){
			int x=q.front(); q.pop();
			for (int i=0;i<G[x].size();i++){
				edge& e=edges[G[x][i]];
				if (vis[e.to]||e.cap<=e.flow) continue;
				d[e.to]=d[x]+1;
				vis[e.to]=1;
				q.push(e.to);
			}
		}
		return vis[t];
	}
	
	int dfs(int x,int a){
		if (x==t||a==0) return a;
		int flow=0,f;
		for (int& i=cur[x];i<G[x].size();i++){
			edge& e=edges[G[x][i]];
			if (d[e.to]==d[x]+1){
				f=dfs(e.to,min(a,e.cap-e.flow));
				if (f>0){
					flow+=f;
					a-=f;
					edges[G[x][i]].flow+=f;
					edges[G[x][i]^1].flow-=f;
					if (a==0) break;
				}
			}
		}
		return flow;
	}
	
	int maxflow(int s,int t,int &flow){
		this->s=s; this->t=t;
		int f;
		while(bfs()){
			memset(cur,0,sizeof(cur));
			flow+=dfs(s,INF);
		}
		return flow;
	}
}nf;

int n,m,s,t;
int u,v,c;

void solve(){
	scanf("%d%d",&n,&m);
	s=maxn-2,t=maxn-1;
	nf.init(t);
	
	int flow=0;
	nf.maxflow(s,t,flow);
	printf("%d\n",flow);
	return;
}

int main(){
	solve();
	return 0;
}

2.费用流

#include<bits/stdc++.h>
#define maxn 10000
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long ll;

const int N = 1000;
const int INF = 0x3f3f3f3f;

struct edge{
	int from,to,flow,cap,cost;
};
class poi{
public:
	vector<edge> edges;
	vector<int> G[maxn];
	int a[maxn];
	int p[maxn];
	int d[maxn];
	bool inq[maxn];
	int n,m,s,t;
	
	void init(int n){
		this->n=n;
		for (int i=0;i<=n;i++) G[i].clear();
		edges.clear();
	}
	
	void addedge(int from,int to,int cap,int cost){
		edges.push_back((edge){from,to,0,cap,cost});
		G[from].push_back(edges.size()-1);
		edges.push_back((edge){to,from,0,0,-cost});
		G[to].push_back(edges.size()-1);
	}
	
	bool spfa(int s,int t,int& flow,int& cost){
		memset(d,0x3f,sizeof(d));
		memset(inq,0,sizeof(inq));
		queue<int> q;
		q.push(s); d[s]=0; inq[s]=1; a[s]=INF; p[s]=0;
		while(!q.empty()){
			int x=q.front();  q.pop(); inq[x]=0;
			for (int i=0;i<G[x].size();i++){
				edge& e=edges[G[x][i]];
				if (d[e.to]>d[e.from]+e.cost&&e.cap>e.flow){
					d[e.to]=d[e.from]+e.cost;
					a[e.to]=min(a[e.from],e.cap-e.flow);
					p[e.to]=G[x][i];
					if (!inq[e.to]){
						inq[e.to]=1;
						q.push(e.to);
					}
				}
			}
		}
		if (d[t]==INF) return 0;
		flow+=a[t];
		cost+=a[t]*d[t];
		int u=t;
		while(u!=s){
			edges[p[u]].flow+=a[t];
			edges[p[u]^1].flow-=a[t];
			u=edges[p[u]].from;
		}
		return 1;
	}
	
	int maxcost(int s,int t,int &flow,int &cost){ 
		for(int i=0;i<edges.size();i+=2){ 
			//如果先跑了一遍最小费用流,需要先清空初始化网络 
			edges[i].flow+=edges[i^1].flow;
			edges[i^1].flow=0;
			//边权取反求最长路 
			edges[i].cost=-edges[i].cost;
			edges[i^1].cost=-edges[i^1].cost;
		}
		mincost(s,t,flow,cost);
		cost=-cost;
		return cost;
	}
	
	int mincost(int s,int t,int &flow,int &cost){
		flow=0,cost=0;
		while(spfa(s,t,flow,cost)){
		}
		return cost;
	}
	
}mc;

int n,m,s,t;


void solve(){
	scanf("%d%d",&n,&m);
	s=0,t=maxn-1;
	mc.init(t);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d%d",&u,&v,&c,&w);
		mc.addedge(u,v,c,w);
	}
	int flow=0,cost=0;
	mc.mincost(s,t,flow,cost);
	printf("%d %d\n",flow,cost);
}

int main(){
	solve();
	return 0;
}

3.二分图染色

int flag;
vector<int> ve[N];
int col[N];
 
int n,m;
struct node{
    int u,v,w;
}g[N];
 
bool cmp(node a,node b)
{
    return a.w<b.w;
}
 
 
bool dfs(int u, int c) {
    col[u] = c;
    for (auto v : ve[u]) {
        if (col[v] == c) return 0;
        if (!col[v] && !dfs(v, -c)) return 0;
    }
    return 1;
}
 
bool ok(int x) {
    for (int i = 1; i <= n; i++)
        ve[i].clear(), col[i] = 0;
    for (int i = 1; i <= m; i++) {
        if (g[i].w > x) {
            ve[g[i].u].push_back(g[i].v);
            ve[g[i].v].push_back(g[i].u);
        }
    }
    for (int i = 1; i <= n; i++)
        if (!col[i]) {
            if (!dfs(i, 1)) return 0;
        }
    return 1;
}

五.数学

1.数论

1.FFT

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;

const double PI = acos(-1.0);
//复数结构体
struct complex
{
    double r,i;
    complex(double _r = 0.0,double _i = 0.0)
    {
        r = _r; i = _i;
    }
    complex operator +(const complex &b)
    {
        return complex(r+b.r,i+b.i);
    }
    complex operator -(const complex &b)
    {
        return complex(r-b.r,i-b.i);
    }
    complex operator *(const complex &b)
    {
        return complex(r*b.r-i*b.i,r*b.i+i*b.r);
    }
};
/*
 * 进行FFT和IFFT前的反转变换。
 * 位置i和 (i二进制反转后位置)互换
 * len必须去2的幂
 */
void change(complex y[],int len)
{
    int i,j,k;
    for(i = 1, j = len/2;i < len-1; i++)
    {
        if(i < j)swap(y[i],y[j]);
        //交换互为小标反转的元素,i<j保证交换一次
        //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
        k = len/2;
        while( j >= k)
        {
            j -= k;
            k /= 2;
        }
        if(j < k) j += k;
    }
}
/*
 * 做FFT
 * len必须为2^k形式,
 * on==1时是DFT,on==-1时是IDFT
 */
void fft(complex y[],int len,int on)
{
    change(y,len);
    for(int h = 2; h <= len; h <<= 1)
    {
        complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(int j = 0;j < len;j+=h)
        {
            complex w(1,0);
            for(int k = j;k < j+h/2;k++)
            {
                complex u = y[k];
                complex t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if(on == -1)
        for(int i = 0;i < len;i++)
            y[i].r /= len;
}
const int MAXN = 200010;
complex x1[MAXN],x2[MAXN];
char str1[MAXN/2],str2[MAXN/2];
int sum[MAXN];
int main()
{
    while(scanf("%s%s",str1,str2)==2)
    {
        int len1 = strlen(str1);
        int len2 = strlen(str2);
        int len = 1;
        while(len < len1*2 || len < len2*2)len<<=1;
        for(int i = 0;i < len1;i++)
            x1[i] = complex(str1[len1-1-i]-'0',0);
        for(int i = len1;i < len;i++)
            x1[i] = complex(0,0);
        for(int i = 0;i < len2;i++)
            x2[i] = complex(str2[len2-1-i]-'0',0);
        for(int i = len2;i < len;i++)
            x2[i] = complex(0,0);
        //求DFT
        fft(x1,len,1);
        fft(x2,len,1);
        for(int i = 0;i < len;i++)
            x1[i] = x1[i]*x2[i];
        fft(x1,len,-1);
        for(int i = 0;i < len;i++)
            sum[i] = (int)(x1[i].r+0.5);
        for(int i = 0;i < len;i++)
        {
            sum[i+1]+=sum[i]/10;
            sum[i]%=10;
        }
        len = len1+len2-1;
        while(sum[len] <= 0 && len > 0)len--;
        for(int i = len;i >= 0;i--)
            printf("%c",sum[i]+'0');
        printf("\n");
    }
    return 0;
}

2.快速幂

int qmi(int a, int k, int p){
    int res = 1;
    while(k){
        if(k & 1) res = (LL) res * a % p;
        k >>= 1;
        a = (LL) a * a % p;
    }
    return res;
}

3.exgcd

//扩展欧几里得算法,计算a和b的最大公约数以及对应的系数
int exgcd(int a, int b, int &x, int &y){
    if(!b){
        y = 0, x = 1;
        return a;//最大公约数为a
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

4.莫比乌斯反演

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

const int N=1e7+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;

int n,m;

int tot,pri[N],phi[N];
ll sum[N],ans;
bool mark[N];

void getphi(int n){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!mark[i]){
			phi[i]=i-1;
			pri[++tot]=i;
		}
		for(int j=1;j<=tot;j++){
			int x=pri[j];
			if(i*x>n)break;
			mark[i*x]=1;
			if(i%x==0){
				phi[i*x]=phi[i]*x;
				break;
			}
			else
				phi[i*x]=phi[i]*phi[x]; 
		}
	}
}

void solve(){
	read(n);
	getphi(n);
	fo(i,1,n){
		sum[i]=sum[i-1]+phi[i];
	}
	fo(i,1,tot){
		ans+=sum[n/pri[i]];
	}
	ans<<=1;
	ans-=tot;
	cout<<ans<<endl;
}


int main(){
//	int T;read(T);
//	for(int i=1;i<=T;i++)
		solve();
}

5.欧拉函数

int phi(int x)
{
    int res = x;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) res = res / x * (x - 1);

    return res;
}

6.高斯消元解线性方程组

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 110;
const double eps = 1e-6;

int n;
double a[N][N];


int gauss()
{
    int c, r;
    for (c = 0, r = 0; c < n; c ++ )
    {
        int t = r;
        for (int i = r; i < n; i ++ )
            if (fabs(a[i][c]) > fabs(a[t][c]))
                t = i;

        if (fabs(a[t][c]) < eps) continue;

        for (int i = c; i < n + 1; i ++ ) swap(a[t][i], a[r][i]);
        for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c];

        for (int i = r + 1; i < n; i ++ )
            if (fabs(a[i][c]) > eps)
                for (int j = n; j >= c; j -- )
                    a[i][j] -= a[r][j] * a[i][c];

        r ++ ;
    }

    if (r < n)
    {
        for (int i = r; i < n; i ++ )
            if (fabs(a[i][n]) > eps)
                return 2;
        return 1;
    }

    for (int i = n - 1; i >= 0; i -- )
        for (int j = i + 1; j < n; j ++ )
            a[i][n] -= a[j][n] * a[i][j];

    return 0;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n + 1; j ++ )
            cin >> a[i][j];

    int t = gauss();

    if (t == 0)
    {
        for (int i = 0; i < n; i ++ ) printf("%.2lf\n", a[i][n]);
    }
    else if (t == 1) puts("Infinite group solutions");
    else puts("No solution");

    return 0;
}

7.矩阵乘法

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 3;

int n, m;

void mul(int c[], int a[], int b[][N])
{
    int temp[N] = {0};
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            temp[i] = (temp[i] + (LL)a[j] * b[j][i]) % m;

    memcpy(c, temp, sizeof temp);
}

void mul(int c[][N], int a[][N], int b[][N])
{
    int temp[N][N] = {0};
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            for (int k = 0; k < N; k ++ )
                temp[i][j] = (temp[i][j] + (LL)a[i][k] * b[k][j]) % m;

    memcpy(c, temp, sizeof temp);
}

int main()
{
    cin >> n >> m;

    int f1[N] = {1, 1, 1};
    int a[N][N] = {
        {0, 1, 0},
        {1, 1, 1},
        {0, 0, 1}
    };

    n -- ;
    while (n)
    {
        if (n & 1) mul(f1, f1, a);  // res = res * a
        mul(a, a, a);  // a = a * a
        n >>= 1;
    }

    cout << f1[2] << endl;

    return 0;
}

8.容斥原理

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 20, mod = 1e9 + 7;

LL A[N];
int down = 1;

int qmi(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

int C(LL a, LL b)
{
    if (a < b) return 0;
    int up = 1;
    for (LL i = a; i > a - b; i -- ) up = i % mod * up % mod;

    return (LL)up * down % mod; // 费马小定理
}

int main()
{
    LL n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i ++ ) cin >> A[i];

    for (int j = 1; j <= n - 1; j ++ ) down = (LL)j * down % mod;
    down = qmi(down, mod - 2, mod);

    int res = 0;
    for (int i = 0; i < 1 << n; i ++ )
    {
        LL a = m + n - 1, b = n - 1;
        int sign = 1;
        for (int j = 0; j < n; j ++ )
            if (i >> j & 1)
            {
                sign *= -1;
                a -= A[j] + 1;
            }
        res = (res + C(a, b) * sign) % mod;
    }

    cout << (res + mod) % mod << endl;

    return 0;
}

9.线性筛

int primes[N], cnt;
bool st[N];

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

10.EXCRT

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

const int N=2e5+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;

int n;

ll qmul(ll a,ll b,ll mod){
	return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
} 

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll g=exgcd(b,a%b,x,y);
	ll tx=x;
	x=y;
	y=tx-(a/b)*y;
	return g;
}

ll excrt(ll* m,ll* a){
	for(int i=2;i<=n;i++){
		ll c=a[i]-a[1],x,y;
		c=(c%m[i]+m[i])%m[i];
		ll g=exgcd(m[1],m[i],x,y);
		x=qmul(x,(c/g),m[i]);
		x=(x%m[i]+m[i])%m[i];
		a[1]=a[1]+qmul(m[1],x,m[1]*(m[i]/g));
		m[1]=m[1]/g*m[i];
		a[1]=(a[1]%m[1]+m[1])%m[1];
	}
	return a[1];
}

ll m[100],a[100];

void solve(){
	read(n);
	fo(i,1,n){
		cin>>m[i]>>a[i];
	}
	cout<<excrt(m,a);
}

int main(){
//	int T;read(T);
//	for(int i=1;i<=T;i++)
		solve();
}

11.原根

#include<cstdio>
#include<cmath>
inline int phi(int n)
{
    int zc=n,all=sqrt(n);
    for(int i=2;i<=all;i++)
	{
		if(n%i!=0)continue;
    	zc=zc/i*(i-1);
    	while(n%i==0)n/=i;
    }
    if(n>1)zc=zc/n*(n-1);
    return zc;
}
inline int pow(int x,const int y,const int mod)
{
	int res=1;
	for(int i=1;i<=y;i<<=1,x=(long long)x*x%mod)if(i&y)res=(long long)res*x%mod;
	return res;
}
int q[100001];
inline int G(const int m)
{
	const int PHI=phi(m);
	q[0]=0;
	const int limit=sqrt(PHI);int zc=PHI;
	for(int i=2;i<=limit;i++)
		if(zc%i==0)
		{
			q[++q[0]]=PHI/i;
			while(zc%i==0)zc/=i;
		}
	if(zc>1)zc=q[++q[0]]=PHI/zc;
	for(int g=2;;g++)
	{
		bool fla=1;
		if(pow(g,PHI,m)!=1)continue;
		for(int i=1;i<=q[0];i++)
			if(pow(g,q[i],m)==1)
			{
				fla=0;
				break;
			}
		if(fla)return g;
	}
}
int m,g;
int main()
{
	scanf("%d",&m);
    g=G(m);
    printf("%d",g);
    return 0;
}

12.博弈论

不平等博弈

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;

//加法: x + y = {XL + y , x + YL | XR + y , x + YR } 
//SN定理:多游戏的 SN 等于子游戏的 SN 的直接加和

double sn[20][20];
double get_sn(int x,int y){
	if(sn[x][y]!=inf) return sn[x][y];
	double l=-inf,r=inf;
	for(int i=1;i<=x/2;i++) l=max(l,get_sn(i,y)+get_sn(x-i,y));//玩家L 操作的后继状态的SN值集合 XL 取最大值 
	for(int i=1;i<=y/2;i++) r=min(r,get_sn(x,i)+get_sn(x,y-i));//玩家R 操作的后继状态的SN值集合 XR 取最小值 
	// 1. l < 0 且 r > 0,SN(x) = 0
	if(l<0&&r>0) sn[x][y]=0;	
	// 2. l , r 中间有整数
	else if(floor(l+1)>l&&floor(l+1)<r){
		if(l>=0) sn[x][y]=floor(l+1);
		else sn[x][y]=ceil(r-1);
	}
	// 3. l , r 中间无整数,优先 k 最小,其次 j 最小,使得 l < j / 2^k < r
	else{
		int j,k,tmp=1;
		bool ok=0;
		for(k=1;!ok;k++){
			tmp<<=1;
			for(j=floor(l*tmp+1);!ok&&j<tmp*r;j++) if(j>l*tmp&&j<r*tmp){
				ok=1;
				break;
			}
		}
		sn[x][y]=1.0*j/tmp;
	}
	return sn[x][y];
}

// x>0,L必胜 ; x<0,R必胜 ; x=0,后手必胜(一定注意是后手必胜,千万别记反了)

int main(){
	for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) sn[i][j]=inf;
	for(int i=1;i<=16;i++) for(int j=1;j<=16;j++) printf("%.0f%c",get_sn(i,j),j==16?'\n':' ');
	return 0;
}

nim积

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2000000
using namespace std;
int m[2][2]={0,0,0,1};
int Nim_Mult_Power(int x,int y){
	if(x<2)
		return m[x][y];
	int a=0;
	for(;;a++)
		if(x>=(1<<(1<<a))&&x<(1<<(1<<(a+1))))
			break;
	int m=1<<(1<<a);
	int p=x/m,s=y/m,t=y%m;
	int d1=Nim_Mult_Power(p,s);
	int d2=Nim_Mult_Power(p,t);
	return (m*(d1^d2))^Nim_Mult_Power(m/2,d1);
}
int Nim_Mult(int x,int y){
	if(x<y)
		return Nim_Mult(y,x);
	if(x<2)
		return m[x][y];
	int a=0;
	for(;;a++)
		if(x>=(1<<(1<<a))&&x<(1<<(1<<(a+1))))
			break;
	int m=1<<(1<<a);
	int p=x/m,q=x%m,s=y/m,t=y%m;
	int c1=Nim_Mult(p,s),c2=Nim_Mult(p,t)^Nim_Mult(q,s),c3=Nim_Mult(q,t);
	return (m*(c1^c2))^c3^Nim_Mult_Power(m/2,c1);
}
int main(){
	int t,n,x,y;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		int ret=0;
		while(n--){
			scanf("%d%d",&x,&y);
			ret^=Nim_Mult(x,y);
		}
		if(ret)
			puts("Have a try, lxhgww.");
		else
			puts("Don't waste your time.");
	}
	return 0;
}

2.组合数学

1.lucas


long long Lucas(long long n, long long m, long long p) {
  if (m == 0) return 1;
  return (C(n % p, m % p, p) * Lucas(n / p, m / p, p)) % p;
}

2.exlucas

int inverse(int x) 函数返回x在模p意义下的逆元
LL CRT(int n, LL* a, LL* m) {
  LL M = 1, p = 0;
  for (int i = 1; i <= n; i++) M = M * m[i];
  for (int i = 1; i <= n; i++) {
    LL w = M / m[i], x, y;
    exgcd(w, m[i], x, y);
    p = (p + a[i] * w * x % mod) % mod;
  }
  return (p % mod + mod) % mod;
}
LL calc(LL n, LL x, LL P) {
  if (!n) return 1;
  LL s = 1;
  for (int i = 1; i <= P; i++)
    if (i % x) s = s * i % P;
  s = Pow(s, n / P, P);
  for (int i = n / P * P + 1; i <= n; i++)
    if (i % x) s = s * i % P;
  return s * calc(n / x, x, P) % P;
}
LL multilucas(LL m, LL n, LL x, LL P) {
  int cnt = 0;
  for (int i = m; i; i /= x) cnt += i / x;
  for (int i = n; i; i /= x) cnt -= i / x;
  for (int i = m - n; i; i /= x) cnt -= i / x;
  return Pow(x, cnt, P) % P * calc(m, x, P) % P * inverse(calc(n, x, P), P) %
         P * inverse(calc(m - n, x, P), P) % P;
}
LL exlucas(LL m, LL n, LL P) {
  int cnt = 0;
  LL p[20], a[20];
  for (LL i = 2; i * i <= P; i++) {
    if (P % i == 0) {
      p[++cnt] = 1;
      while (P % i == 0) p[cnt] = p[cnt] * i, P /= i;
      a[cnt] = multilucas(m, n, i, p[cnt]);
    }
  }
  if (P > 1) p[++cnt] = P, a[cnt] = multilucas(m, n, P, P);
  return CRT(cnt, a, p);
}

3.预处理阶乘计算组合数

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, mod = 1e9 + 7;


int fact[N], infact[N];


int qmi(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}


int main()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++ )
    {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }


    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }

    return 0;
}


4.组合数大礼包

struct AC
{
    static const int maxn = 1e6+10;
    ll f[maxn];
    void init(int mod){ //预处理阶乘
        f[0] = 1;
        for(int i = 1;i<maxn;i++) f[i] = f[i-1]*i%mod;
    }
    ll ksm(ll a,ll b,ll mod){
        ll ans = 1;
        while(b){
            if(b&1) ans = ans*a%mod;
            a = a*a%mod;
            b>>=1;
        }
        return ans;
    }
    ll C_mod(ll n,ll m,ll mod){//组合数%mod
        return f[n] * ksm(f[m] * f[n-m]%mod,mod-2,mod)%mod;
    }
    ll lucas_mod(ll n,ll m,ll mod){
        return m? C_mod(n%mod,m%mod,mod) * lucas_mod(n/mod,m/mod,mod)%mod : 1;
    }
    ll A(ll n, ll r)//排列数
    {    
        ll sum = 1;
        for (int i = 0; i < r; i++)
            sum *= n-i;
        return sum;
    }
    ll C(ll n,ll K){ //组合数
        if(K>n) return 0;
        if(K > n-K) K = n-K;
        ll m = 1,s = 1;
        for(int i = 0;i<K;i++){
            m = m*(n-i);
            s = s*(i+1);
        }
        return m/s;
    }
}ac;

5.排列组合

ll A(ll n, ll r)//排列数
{    ll sum = 1;
    for (int i = 0; i < r; i++)
        sum *= n-i;
    return sum;
}
ll C(ll n, ll r)//组合数
{    ll sum = 1;
    for (int i = 1; i <= r; i++)
        sum = sum * (n+1-i)/i;
    return sum;
}

3.计算几何

1.模拟退火

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>

const int N = 10005;
int n, x[N], y[N], w[N];
double ansx, ansy, dis;

double Rand() { return (double)rand() / RAND_MAX; }
double calc(double xx, double yy) {
  double res = 0;
  for (int i = 1; i <= n; ++i) {
    double dx = x[i] - xx, dy = y[i] - yy;
    res += sqrt(dx * dx + dy * dy) * w[i];
  }
  if (res < dis) dis = res, ansx = xx, ansy = yy;
  return res;
}
void simulateAnneal() {
  double t = 100000;
  double nowx = ansx, nowy = ansy;
  while (t > 0.001) {
    double nxtx = nowx + t * (Rand() * 2 - 1);
    double nxty = nowy + t * (Rand() * 2 - 1);
    double delta = calc(nxtx, nxty) - calc(nowx, nowy);
    if (exp(-delta / t) > Rand()) nowx = nxtx, nowy = nxty;
    t *= 0.97;
  }
  for (int i = 1; i <= 1000; ++i) {
    double nxtx = ansx + t * (Rand() * 2 - 1);
    double nxty = ansy + t * (Rand() * 2 - 1);
    calc(nxtx, nxty);
  }
}
int main() {
  srand(time(0));
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    scanf("%d%d%d", &x[i], &y[i], &w[i]);
    ansx += x[i], ansy += y[i];
  }
  ansx /= n, ansy /= n, dis = calc(ansx, ansy);
  simulateAnneal();
  printf("%.3lf %.3lf\n", ansx, ansy);
  return 0;
}

六.动态规划

1.数位DP

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

//给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数

const int N=2e5+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;

int n,m;

ll dp[21][200][200];
int a[N];

ll dfs(ll pos,ll num,ll mod,ll rem,bool limit){
	if (num<0||num>pos*9){
		return 0;
	}
	if (pos==0){
		return num==0&&rem==0;
	}
	if (dp[pos][num][rem]!=-1&&limit==false){
		return dp[pos][num][rem];
	}
	int up=limit?a[pos]:9;
	ll sum=0;
	for(int i=0;i<=up;i++){
		sum+=dfs(pos-1,num-i,mod,(rem*10+i)%mod,limit&&i==a[pos]);
	}
	if (!limit){
		dp[pos][num][rem]=sum;
	}
	return sum;
}

ll solve(ll x){
	int len=0;
	while(x){
		a[++len]=x%10;
		x/=10;
	}
	ll sum=0;
	for(int i=1;i<=len*9;i++){
		memset(dp,-1,sizeof(dp));
		sum+=dfs(len,i,i,0,1);
	}
	return sum;
}

int main(){
//	ios::sync_with_stdio(0);
//  cin.tie(0),cout.tie(0);
//	int T;read(T);
//	for(int i=1;i<=T;i++)
	ll a,b;
	cin>>a>>b;
	cout<<solve(b)-solve(a-1);
}

&n);
while (n – )
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}

return 0;

}


### 4.组合数大礼包

```c++
struct AC
{
    static const int maxn = 1e6+10;
    ll f[maxn];
    void init(int mod){ //预处理阶乘
        f[0] = 1;
        for(int i = 1;i<maxn;i++) f[i] = f[i-1]*i%mod;
    }
    ll ksm(ll a,ll b,ll mod){
        ll ans = 1;
        while(b){
            if(b&1) ans = ans*a%mod;
            a = a*a%mod;
            b>>=1;
        }
        return ans;
    }
    ll C_mod(ll n,ll m,ll mod){//组合数%mod
        return f[n] * ksm(f[m] * f[n-m]%mod,mod-2,mod)%mod;
    }
    ll lucas_mod(ll n,ll m,ll mod){
        return m? C_mod(n%mod,m%mod,mod) * lucas_mod(n/mod,m/mod,mod)%mod : 1;
    }
    ll A(ll n, ll r)//排列数
    {    
        ll sum = 1;
        for (int i = 0; i < r; i++)
            sum *= n-i;
        return sum;
    }
    ll C(ll n,ll K){ //组合数
        if(K>n) return 0;
        if(K > n-K) K = n-K;
        ll m = 1,s = 1;
        for(int i = 0;i<K;i++){
            m = m*(n-i);
            s = s*(i+1);
        }
        return m/s;
    }
}ac;

5.排列组合

ll A(ll n, ll r)//排列数
{    ll sum = 1;
    for (int i = 0; i < r; i++)
        sum *= n-i;
    return sum;
}
ll C(ll n, ll r)//组合数
{    ll sum = 1;
    for (int i = 1; i <= r; i++)
        sum = sum * (n+1-i)/i;
    return sum;
}

3.计算几何

1.模拟退火

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>

const int N = 10005;
int n, x[N], y[N], w[N];
double ansx, ansy, dis;

double Rand() { return (double)rand() / RAND_MAX; }
double calc(double xx, double yy) {
  double res = 0;
  for (int i = 1; i <= n; ++i) {
    double dx = x[i] - xx, dy = y[i] - yy;
    res += sqrt(dx * dx + dy * dy) * w[i];
  }
  if (res < dis) dis = res, ansx = xx, ansy = yy;
  return res;
}
void simulateAnneal() {
  double t = 100000;
  double nowx = ansx, nowy = ansy;
  while (t > 0.001) {
    double nxtx = nowx + t * (Rand() * 2 - 1);
    double nxty = nowy + t * (Rand() * 2 - 1);
    double delta = calc(nxtx, nxty) - calc(nowx, nowy);
    if (exp(-delta / t) > Rand()) nowx = nxtx, nowy = nxty;
    t *= 0.97;
  }
  for (int i = 1; i <= 1000; ++i) {
    double nxtx = ansx + t * (Rand() * 2 - 1);
    double nxty = ansy + t * (Rand() * 2 - 1);
    calc(nxtx, nxty);
  }
}
int main() {
  srand(time(0));
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    scanf("%d%d%d", &x[i], &y[i], &w[i]);
    ansx += x[i], ansy += y[i];
  }
  ansx /= n, ansy /= n, dis = calc(ansx, ansy);
  simulateAnneal();
  printf("%.3lf %.3lf\n", ansx, ansy);
  return 0;
}

六.动态规划

1.数位DP

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define read(x) scanf("%d",&x)
typedef long long ll;
typedef double dl;
using namespace std;

//给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数

const int N=2e5+7;
const int M=1e9+7;
const int INF=0x3f3f3f3f;

int n,m;

ll dp[21][200][200];
int a[N];

ll dfs(ll pos,ll num,ll mod,ll rem,bool limit){
	if (num<0||num>pos*9){
		return 0;
	}
	if (pos==0){
		return num==0&&rem==0;
	}
	if (dp[pos][num][rem]!=-1&&limit==false){
		return dp[pos][num][rem];
	}
	int up=limit?a[pos]:9;
	ll sum=0;
	for(int i=0;i<=up;i++){
		sum+=dfs(pos-1,num-i,mod,(rem*10+i)%mod,limit&&i==a[pos]);
	}
	if (!limit){
		dp[pos][num][rem]=sum;
	}
	return sum;
}

ll solve(ll x){
	int len=0;
	while(x){
		a[++len]=x%10;
		x/=10;
	}
	ll sum=0;
	for(int i=1;i<=len*9;i++){
		memset(dp,-1,sizeof(dp));
		sum+=dfs(len,i,i,0,1);
	}
	return sum;
}

int main(){
//	ios::sync_with_stdio(0);
//  cin.tie(0),cout.tie(0);
//	int T;read(T);
//	for(int i=1;i<=T;i++)
	ll a,b;
	cin>>a>>b;
	cout<<solve(b)-solve(a-1);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值