版权声明:本文为博主原创文章,如果转走了就评论说一声就好了哈。 https://blog.csdn.net/qq_36124802/article/details/80473338
离散化模板:
//把需要离散化的内容进行排序,去重,然后getid为取得这个值的下标
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int getid(int x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1; //错1次,返回下标需要-v.begin()+1
}
链式前向星:
struct E{
int next,to;
}e[maxn+maxn]; //链式前向星要开双倍的大小
void add(int u,int v){
tot++;
e[tot].to=v;
e[tot].next=head[u];
head[u]=tot;
}
三种树状数组(每次操作复杂度均为logn):
1、区间求值,单点修改(基本用法。但是这里可用用作权值树状数组,可以用来查比a[i]大但是下标在i前面的数量
ll lowbits(ll x){
return x&(-x);
}
ll NN;
ll c1[maxn];//注意这里空间可能要开大一些
ll sum(ll x){
ll sum1=0;
while(x>0){
sum1+=c1[x];
x-=lowbits(x);
}
return sum1;
}
ll add(ll x,ll y){
while(x<=NN){
c1[x]+=y;
x+=lowbits(x);
}
}
2、单点求值,区间修改(区间加
ll l=3;
ll r=7,k=10;
add(l,k);
add(r+k,-k);//表示对区间[l,r]+k,查询某个点只需要查询sum(i)即为答案
3、区间求值,区间修改(区间加
int NN,c1[maxn],c2[maxn];
int lowbits(int x){ return x&(-x);}
void add(int *r,int pos,int v){
while(pos<=NN){
r[pos]+=v;
pos+=lowbits(pos);
}
}
int sigma(int *r,int pos){
int anx=0;
while(pos>0){
anx+=r[pos];
pos-=lowbits(pos);
}
return anx;
}
c1与c2均为数组传入,对[f1,f2]+f3
add(c1,f1,f3);add(c1,f2+1,-f3);
add(c2,f1,f3*(f1-1));add(c2,f2+1,-f3*f2);
查询[f1,f2]
sum1=(f1-1)*sigma(c1,f1-1)-sigma(c2,f1-1);
sum2=f2*sigma(c1,f2)-sigma(c2,f2);
cout << sum2-sum1 << endl;
并查集:
先init初始化,find1为寻找其的head,find2为并
int find1(int x){
int r=x;
while(r!=pre[r]){
r=pre[r];
}
int i=x,j;
while(pre[i]!=r){
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
int find2(int x,int y){
int x1=find1(x);
int y1=find1(y);
if(pre[x1]!=pre[y1]){
pre[x1]=pre[y1];
}
}
二分图匹配:
记得在for循环中,赋值vis全部为0,从左边点找右边点,但是算谁连接谁点时候应该从右边点点向前找pre
int bfs(int x){//最后pre[i]=x,表示i被X连接
for(int i=0;i<out[x].size();i++){
int v=out[x][i];
if(vis[v]==0){
vis[v]=1;
if(pre[v]==-1||bfs(pre[v])){
pre[v]=x; //X之前连接点为out[x][i]
return 1;//这里点目的是求出最大匹配的数量
}
}
}
return 0;
}
通过逆元求组合数:
int inv(int a)
{
//return fpow(a, MOD-2, MOD);
return a==1?1:(long long)(MOD-MOD/a)*inv(MOD%a)%MOD;
}
LL C(LL n,LL m)
{
if(m<0)return 0;
if(n<m)return 0;
if(m>n-m)m=n-m;
LL up=1,down=1;
for(LL i=0;i<m;i++)
{
up=up*(n-i)%MOD;
down=down*(i+1)%MOD;
}
return up*inv(down)%MOD;
}
二进制压缩的背包DP:
for(i=1;i<=n;i++){
for(j=0;j<q1[i].num;j++){ //因为是2^k-1个,所以取的时候是1/2/4/8/2^(k-1)刚好全部覆盖
for(k=10000;k>=q1[i].v;k--){
if(k-(1<<j)*q1[i].v<0)break;
res[k]+=res[k-(1<<j)*q1[i].v];
res[k]%=mod;
}
}
}
矩阵快速幂板子:
const int N = 9;
struct Mat{
ll m[N][N];
void clear(){memset(m,0,sizeof(m));}
void I(){for (int i=0;i<N;i++) m[i][i]=1;}
};
Mat mul(const Mat &a, const Mat &b){
Mat c;c.clear();
for (int i=0;i<N;i++)
for (int j=0;j<N;j++){
for (int k=0;k<N;k++)
c.m[i][j]+=a.m[i][k]*b.m[k][j]%mod;
c.m[i][j]%=mod;
}
return c;
}
Mat qpow(Mat a, ll x){ //这里注意传进来的参数要为long long 不然会报超时
Mat ans; ans.clear(); ans.I();
for (;x;a=mul(a,a),x>>=1)
if (x&1)
ans=mul(ans,a);
return ans;
}
Mat t2=(Mat){{
{0,0},
{1,0}
}}; //初始化一个矩阵可以这么写出来
读入挂:
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;
}
树剖的方法求LCA:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+7;
struct node{
int to,next;
};
node edge[maxn+maxn]; //链式前向星开双倍
int cnt,head[maxn],pos;//注意初始化cnt和head为-1
void add(int x,int y){
cnt++;
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
int son[maxn],deep[maxn],fa[maxn],num[maxn];
void init(){
pos=0;
memset(son,-1,sizeof(son));//点的编号从1开始
}
void dfs(int u,int pre,int w){
deep[u]=w;//层数
num[u]=1;//子节点数量
fa[u]=pre;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(v==pre)continue;
dfs(v,u,w+1);
num[u]+=num[v];
if(son[u]==-1||num[son[u]]<num[v])
son[u]=v;
}
}
int p[maxn],fp[maxn],tp[maxn];
//p表示这个点的位置在哪(线段树中的下标)
//fp表示这个位置指哪一个点建树的时候就这么建
//tp表示v在哪个重链上
void dfs2(int u,int sd){
p[u]=++pos;fp[pos]=u;tp[u]=sd;
if(son[u]==-1)return ;
dfs2(son[u],sd);
for(int i=head[u];i!=-1;i=edge[i].next){ //注意head[u]
int v=edge[i].to;
if(v==son[u]||v==fa[u])continue;
dfs2(v,v); //此时v为新链
}
}
int LCA(int u,int v){
int uu=tp[u],vv=tp[v];
while(uu!=vv){
if(deep[vv]>deep[uu]){
swap(uu,vv);swap(u,v);
}
//从左边往右边应该是p[uu],p[u]
u=fa[u];uu=tp[u];
}
if(deep[u]>deep[v])swap(u,v);
//p[u],p[v] //u为根节点
return u;
}
int main(){
int i,j,k,f1,f2,f3,f4,f5,t1,t2,t3,t4,t5;
//freopen("in.txt","r",stdin);
int n,m,Q,S;
scanf("%d %d %d",&n,&Q,&S);
cnt=0;
memset(head,-1,sizeof(head));
init();
for(i=1;i<n;i++){
scanf("%d %d",&t1,&t2);
add(t1,t2);
add(t2,t1);
}
dfs(S,-1,1);
dfs2(S,S);
for(i=1;i<=Q;i++){
scanf("%d %d",&t1,&t2);
printf("%d\n",LCA(t1,t2));
}
return 0;
}