您的位置:首页 > 理论基础 > 数据结构算法

数据结构&&图论板子

2017-11-08 11:40 288 查看

板子日DAY1

以下均为洛谷模板

线段树

(区间修改区间求和)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
ll read(){
char c=getchar();
ll f=1,ans=0;
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c)){
ans=ans*10+(c-'0');
c=getchar();
}
return ans*f;
}
const int maxn=1e5+10;
#define lson x<<1
#define rson x<<1|1
ll sum[maxn<<2],tag[maxn<<2],num[maxn<<2],a[maxn];
inline void pushup(int x){
sum[x]=sum[lson]+sum[rson];
}
inline void pushdown(int x){
if(tag[x]){
tag[lson]+=tag[x];
tag[rson]+=tag[x];
sum[lson]+=tag[x]*num[lson];
sum[rson]+=tag[x]*num[rson];
tag[x]=0;
}
}
void build(int l,int r,int x){
if(l==r){
sum[x]=a[l];
num[x]=1;
return ;
}
ll mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(x);
num[x]=num[lson]+num[rson];
}
void modify(int l,int r,int ql,int qr,int x,int k){
if(ql<=l&&r<=qr){
sum[x]+=num[x]*k;
tag[x]+=k;
return ;
}
pushdown(x);
ll mid=l+r>>1;
if(ql<=mid) modify(l,mid,ql,qr,lson,k);
if(mid<qr) modify(mid+1,r,ql,qr,rson,k);
pushup(x);
}
ll query(int l,int r,int ql,int qr,int x){
if(ql<=l&&r<=qr){
return sum[x];
}
pushdown(x);
ll mid=l+r>>1;
ll ans=0;
if(ql<=mid) ans+=query(l,mid,ql,qr,lson);
if(qr>mid) ans+=query(mid+1,r,ql,qr,rson);
return ans;
}
int main(){
int n=read(),m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
build(1,n,1);
for(int i=1;i<=m;i++){
int ord=read();
if(ord==1){
int x=read(),y=read(),k=read();
modify(1,n,x,y,1,k);
}
else {
int x=read(),y=read();
cout<<query(1,n,x,y,1)<<"\n";
}
}
}


树状数组

(单点修改区间求和)

const int maxn=500100;
int c[maxn],n,m;
int lowbit(int x){
return x&(-x);
}
void add(int x,int k){
while(x<=n){
c[x]+=k;
x+=lowbit(x);
}
}
ll query(int x){
ll ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
//ios::sync_with_stdio(false);
n=read(),m=read();
for(int i=1;i<=n;i++){
int a=read();
add(i,a);
}
for(int i=1;i<=m;i++){
int ord=read();
if(ord==1){
int x=read(),k=read();
add(x,k);
}else {
int x=read(),y=read();
cout<<query(y)-query(x-1)<<"\n";
}
}
return 0;
}


单源最短路

SPFA

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
#include<cmath>
#include<map>
#include<set>
#define ll long long
using namespace std;

ll read()
{
ll ans=0;
bool b=1;
char c=getchar();
while(!isdigit(c))
{
if(c=='-')b=0;
c=getchar();
}
while(isdigit(c))
{
ans=ans*10+(c-'0');
c=getchar();
}
if(b)return ans;
else return -ans;
}
const int maxn=500100;
struct rec{
int t,next,w;
}e[maxn<<1];
int now[maxn],f[maxn],dis[maxn],p,pre[maxn];
inline void add(int a,int b,int c){
p+
15f6e
+;
e[p].t=b;
e[p].w=c;
e[p].next=now[a];
now[a]=p;
}
void dfs(int x){
if(pre[x])dfs(pre[x]);
cout<<x<<" ";
}
int main()
{
//ios::sync_with_stdio(false);
queue<int> que;
int n=read(),m=read(),s=read();
for(int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
add(a,b,c);
//add(b,a,c); 一定要看是单向边还是双向边!!!
}
for(int i=1;i<=n;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
que.push(s);f[s]=1;
while(!que.empty()){
int u=que.front();
que.pop();
f[u]=0;
for(int i=now[u];i;i=e[i].next){
int v=e[i].t;
if(dis[u]+e[i].w<dis[v]){
dis[v]=dis[u]+e[i].w;
pre[v]=u;
if(!f[v]){
f[v]=1;
que.push(v);
}
}
}
}
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
//dfs(i);cout<<endl; //输出路径
}
return 0;
}


朴素的Dijkstra

for(int i=1;i<=n;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
for(int i=1;i<=n;i++){
int minn=0x7fffffff,u=-1;
for(int j=1;j<=n;j++){
if(dis[j]<minn&&!vis[j]){
minn=dis[j],u=j;
}
}
if(u==-1)break;
vis[u]=1;
for(int j=now[u];j;j=e[j].next){
int v=e[j].t;
if(!vis[v])
dis[v]=min(dis[u]+e[j].w,dis[v]);
}
}


堆优化的DJ

typedef pair<int,int> kkk;
priority_queue<kkk,vector<kkk>,greater<kkk> > que;
int n=read(),m=read(),s=read();
for(int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
add(a,b,c);
}
for(int i=1;i<=n;i++){
dis[i]=0x7fffffff;
}
dis[s]=0;
que.push(make_pair(0,s));
while(!que.empty()){
kkk top=que.top();
int u=top.second;
que.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=now[u];i;i=e[i].next){
int v=e[i].t;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
que.push(make_pair(dis[v],v));
}
}
}


树链剖分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
ll read(){
char c=getchar();
ll f=1,ans=0;
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c)){
ans=ans*10+(c-'0');
c=getchar();
}
return ans*f;
}
const int maxn=1e5+10;
#define lson x<<1
#define rson x<<1|1
ll sum[maxn<<2],tag[maxn<<2],num[maxn<<2],a[maxn],r,n,m,p;
inline void pushup(int x){
sum[x]=sum[lson]+sum[rson];
}
inline void pushdown(int x){
if(tag[x]){
tag[lson]+=tag[x];
tag[lson]%=p;
tag[rson]+=tag[x];
tag[rson]%=p;
sum[lson]+=tag[x]*num[lson];
sum[lson]%=p;
sum[rson]+=tag[x]*num[rson];
sum[rson]%=p;
tag[x]=0;
}
}
void build(int l,int r,int x){
if(l==r){
sum[x]=a[l];
num[x]=1;
return ;
}
ll mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(x);
num[x]=num[lson]+num[rson];
}
void modify(int l,int r,int ql,int qr,int x,int k){
if(ql<=l&&r<=qr){
sum[x]+=num[x]*k;
sum[x]%=p;
tag[x]+=k;
tag[x]%=p;
return ;
}
pushdown(x);
ll mid=l+r>>1;
if(ql<=mid) modify(l,mid,ql,qr,lson,k);
if(mid<qr) modify(mid+1,r,ql,qr,rson,k);
pushup(x);
}
ll query(int l,int r,int ql,int qr,int x){
if(ql<=l&&r<=qr){
return sum[x];
}
pushdown(x);
ll mid=l+r>>1;
ll ans=0;
if(ql<=mid) ans+=query(l,mid,ql,qr,lson);
ans%=p;
if(qr>mid) ans+=query(mid+1,r,ql,qr,rson);
ans%=p;
return ans;
}
ll size[maxn],top[maxn],son[maxn],dep[maxn],fa[maxn],now[maxn],dfn[maxn],cnt,w[maxn],pp;
struct rec{
int t,next;
}e[maxn<<2];
void dfs_1(int x){
size[x]=1;
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(v!=fa[x]){
fa[v]=x;
dep[v]=dep[x]+1;
dfs_1(v);
size[x]+=size[v];
if(size[son[x]]<size[v])son[x]=v;
}
}
}
void dfs_2(int x,int t){
dfn[x]=++cnt;
a[cnt]=w[x];
top[x]=t;
if(son[x])dfs_2(son[x],t);
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(v!=fa[x]&&v!=son[x]){
dfs_2(v,v);
}
}
}
void cal(int a,int b,int k){
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])a^=b^=a^=b;
modify(1,n,dfn[top[a]],dfn[a],1,k);
a=fa[top[a]];
}
if(dep[a]>dep[b])a^=b^=a^=b;
modify(1,n,dfn[a],dfn[b],1,k);
}
ll call(int a,int b){
ll ans=0;
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])a^=b^=a^=b;
ans+=query(1,n,dfn[top[a]],dfn[a],1);
ans%=p;
a=fa[top[a]];
}
if(dep[a]>dep[b])a^=b^=a^=b;
ans+=query(1,n,dfn[a],dfn[b],1);
ans%=p;
return ans;
}
void add(int a,int b){
pp++;
e[pp].t=b;
e[pp].next=now[a];
now[a]=pp;
}
int main(){
n=read(),m=read(),r=read(),p=read();
for(int i=1;i<=n;i++){
w[i]=read();
}
for(int i=1;i<n;i++){
int a=read(),b=read();
add(a,b);
add(b,a);
}
dfs_1(r);
dfs_2(r,r);
build(1,n,1);
for(int i=1;i<=m;i++){
int ord=read();
if(ord==1){
int x=read(),y=read(),k=read();
cal(x,y,k);
}
else if(ord==2){
int x=read(),y=read();
cout<<call(x,y)<<"\n";
}
else if(ord==3){
int x=read(),k=read();
modify(1,n,dfn[x],dfn[x]+size[x]-1,1,k);
}
else {
int x=read();
cout<<query(1,n,dfn[x],dfn[x]+size[x]-1,1)<<"\n";
}
}
}


三分法

double xishu[20];
int n;
double poww(double x,int p){
double ans=1.0;
for(;p;p>>=1,x=x*x){
if(p&1){
ans=ans*x;
}
}
return ans;
}
double f(double x){
double ans=0.0;
for(int i=0;i<=n;i++){
ans+=poww(x,i)*xishu[i];
}
return ans;
}
const double eps=1e-7;
int main()
{
//ios::sync_with_stdio(false);
n=read();
double l,r;
cin>>l>>r;
for(int i=n;i>=0;i--){
cin>>xishu[i];
}
double midl,midr;
while(fabs(r-l)>eps&&l<=r){
midl=(r+l)/2,midr=(r+midl)/2;
if(f(midl)>f(midr)) r=midr;
else l=midl;
}
printf("%.5f",l);
return 0;
}


并查集

const int maxn=10100;
int fa[maxn];
int find(int x){
return fa[x]==x? x : fa[x]=find(fa[x]);
}
int main()
{
//ios::sync_with_stdio(false);
int n=read(),m=read();
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int ord=read();
if(ord==1){
int a=read(),b=read();
fa[find(a)]=find(b);
}
else {
int a=read(),b=read();
if(find(a)==find(b))cout<<"Y\n";
else cout<<"N\n";
}
}
return 0;
}


最小生成树

(kruskal)

void kruskal(){
for(int i=1;i<=n;i++){
fa[i]=i;
}
int ans=0,sum=0;
sort(e+1,e+p+1,cmp);
for(int i=1;i<=p;i++){
if(find(e[i].f)!=find(e[i].t)){
fa[find(e[i].f)]=find(e[i].t);
ans+=e[i].w;
sum++;
if(sum==n-1)break;
}
}
if(sum==n-1)cout<<ans;
else cout<<"NO solution";
return;
}


字符串哈希

(哈希表)

const int base = 2000327;
const int MOD = 1e5+7;
struct rec{
string s;
rec *next;
rec():next(NULL) {
}
}hash[MOD];
int find(rec &a,string s){
if(a.next==NULL){
a.s=s;
a.next=new rec;
return 0;
}
if(a.s==s)return 1;
else return find(*(a.next),s);
}
bool haxi(string s){
unsigned long long hia;
for(int i=0;i<s.size();i++){
hia+=base*hia+s[i];   //注意这里
}
hia%=MOD;
if(find(hash[hia],s))return 0;
else return 1;
}
int main()
{
//ios::sync_with_stdio(false);
int n=read(),sum=0;
for(int i=1;i<=n;i++){
string s;
cin>>s;
if(haxi(s)) sum++;
}
cout<<sum;
return 0;
}


(双模)//拒绝吐槽模数

const int MOD1 = 2000327;
const int MOD2 = 2000321;
const int base = 19260817;
int hash1[MOD1],hash2[MOD2];
int find(unsigned long long  haxishu){
unsigned ll ha1=haxishu%MOD1;
unsigned ll ha2=haxishu%MOD2;
if(hash1[ha1]&&hash2[ha2]){
return 1;
}
else {
hash1[ha1]=1;
hash2[ha2]=1;
return 0;
}
}
bool haxi(string s){
unsigned long long hia;
for(int i=0;i<s.size();i++){
hia=base*hia+s[i];
}
if(find(hia))return 0;
else return 1;
}


LCA

(树链剖分)

const int maxn=500100;
struct rec{
int f,t,next;
}e[maxn<<1];
int fa[maxn],size[maxn],top[maxn],son[maxn],dep[maxn],cnt,n,p,m,s,now[maxn];
void add(int a,int b){
p++;
e[p].t=b;
e[p].next=now[a];
now[a]=p;
}
void dfs_1(int x){
size[x]=1;
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(v!=fa[x]){
fa[v]=x;
dep[v]=dep[x]+1;
dfs_1(v);
size[x]+=size[v];// size[v] 噢不是x
if(size[son[x]]<size[v])son[x]=v;
}
}
}
void dfs_2(int x,int t){
top[x]=t;
if(son[x])dfs_2(son[x],t);
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(v!=fa[x]&&v!=son[x]){
dfs_2(v,v);
}
}
}
int lca(int a,int b){
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]]){
a^=b^=a^=b;
}
a=fa[top[a]];
}
if(dep[a]>dep[b])a^=b^=a^=b;
return a;
}
int main()
{
//ios::sync_with_stdio(false);
n=read(),m=read(),s=read();
for(int i=1;i<n;i++){
int a=read(),b=read();
add(a,b);
add(b,a);
}
//fa[s]=s;
dfs_1(s);
dfs_2(s,s);
for(int i=1;i<=m;i++){
int a=read(),b=read();
cout<<lca(a,b)<<"\n";
}
return 0;
}


(倍增)

const int maxn=501000;
struct rec{
int f,t,next;
}e[maxn<<1];
int n,m,s,now[maxn],fa[maxn][20],dep[maxn],p;//注意数组大小 后边for循环不要越界!!
void add(int a,int b){
p++;
e[p].t=b;
e[p].next=now[a];
now[a]=p;
}

void dfs(int x){
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(v!=fa[x][0]){
fa[v][0]=x;
dep[v]=dep[x]+1;
dfs(v);
}
}
}
void befor(){
dfs(s);fa[s][0]=s;//根节点父亲是自己
for(int i=1;i<=17;i++){
for(int j=1;j<=n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
}
int lca(int a,int b){
if(dep[a]<dep[b]){
a^=b^=a^=b;
}
for(int i=17;i>=0;i--){
if(dep[fa[a][i]]>=dep[b]){
a=fa[a][i];
}
}
if(a==b)return a;
for(int i=17;i>=0;i--){
if(fa[a][i]!=fa[b][i]){
a=fa[a][i];
b=fa[b][i];
}
}
a=fa[a][0];
return a;
}
int main()
{
//ios::sync_with_stdio(false);
n=read(),m=read(),s=read();
for(int i=1;i<n;i++){
int a=read(),b=read();
add(a,b);
add(b,a);
}
befor();
for(int i=1;i<=m;i++){
int a=read(),b=read();
cout<<lca(a,b)<<"\n";
}
return 0;
}


负环

dfs_spfa判断

const int maxn=501000;
struct rec{
int f,t,next,w;
}e[maxn<<1];
int n,m,s,now[maxn],dis[maxn],p,vis[maxn];
bool flag;
void add(int a,int b,int c){
p++;
e[p].t=b;
e[p].next=now[a];
e[p].w=c;
now[a]=p;
}
void dfs_spfa(int u){
vis[u]=1;
for(int i=now[u];i;i=e[i].next){
int v=e[i].t;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(vis[v]||flag){
flag=1;
return;
}
else dfs_spfa(v);
}
}
vis[u]=0;
}
int main()
{
//ios::sync_with_stdio(false);
int T=read();
while(T--){
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
memset(now,0,sizeof(now));
p=0;flag=0; //记得每次清零!
n=read(),m=read();
for(int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
add(a,b,c);
if(c>=0)add(b,a,c);
}
for(int i=1;i<=n;i++){
dfs_spfa(i);
if(flag)break;
}
if(flag)cout<<"YE5\n";
else cout<<"N0\n";
}
return 0;
}


二分图匹配

(匈牙利算法)

const int maxn=501000;
struct rec{
int f,t,next;
}e[maxn<<1];
int n,m,s,now[maxn],p,match[maxn],check[maxn],sum=0;
void add(int a,int b){
p++;
e[p].t=b;
e[p].next=now[a];
now[a]=p;
}
bool dfs(int x){
for(int i=now[x];i;i=e[i].next){
int v=e[i].t;
if(!check[v]){ //先检查是否被check过
check[v]=1;//写在前面噢记得
if(!match[v]||dfs(match[v])){ // dfs的是match[v]而不是v
match[x]=v;
match[v]=x;
return 1;
}
}

}
return 0;
}
int main()
{
//ios::sync_with_stdio(false);
int n=read(),m=read(),e=read();
for(int i=1;i<=e;i++){
int a=read(),b=read();
if(b>m)continue;
add(a,b+n);
}
for(int i=1;i<=n;i++){
if(!match[i]){
memset(check,0,sizeof(check));//每次初始化
if(dfs(i)) sum++;
}
}
cout<<sum;
return 0;
}


缩点

(tarjan)

const int maxn=1e5+7;
struct rec{
int t,f,next;
}e1[maxn<<1],e2[maxn<<1];
int now1[maxn],now2[maxn],p,pp,dfn[maxn],low[maxn],cnt,bcnt,w[maxn],bw[maxn],belong[maxn],instack[maxn],dp[maxn];
void add(int a,int b,rec e[],int now[],int &p){
p++;
e[p].t=b;
e[p].f=a;
e[p].next=now[a];
now[a]=p;
}
stack <int> st;
void tarjan(int x){
dfn[x]=low[x]=++cnt;
instack[x]=1;
st.push(x);
for(int i=now1[x];i;i=e1[i].next){
int v=e1[i].t;
if(!dfn[v]){
tarjan(v); //tarjan 不是 dfs
low[x]=min(low[v],low[x]);
}
else if(instack[v]) low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
int j;
++bcnt;
do{
j=st.top();
st.pop();
belong[j]=bcnt;
bw[bcnt]+=w[j];
instack[j]=0; //五项  一项都不能丢!
}while(x!=j);
}
}
int dfs(int x){
if(dp[x])return dp[x];
for(int i=now2[x];i;i=e2[i].next){
int v=e2[i].t;
dp[x]=max(dfs(v),dp[x]);
}
dp[x]+=bw[x]; //加bw 不是w
return dp[x];
}
int main()
{
//ios::sync_with_stdio(false);
int n=read(),m=read();
for(int i=1;i<=n;i++){
w[i]=read();
}
for(int i=1;i<=m;i++){
int a=read(),b=read();
add(a,b,e1,now1,p);
}
for(int i=1;i<=n;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=m;i++){
if(belong[e1[i].f]!=belong[e1[i].t]){
add(belong[e1[i].f],belong[e1[i].t],e2,now2,pp);
}
}  //记得重新加一次边
int ans=0;
for(int i=1;i<=bcnt;i++){
if(!dp[i]){
ans=max(dfs(i),ans);
}
}
cout<<ans;
return 0;
}


割点

(tarjan)

void tarjan(int x){
dfn[x]=low[x]=++cnt;
for(int i=now1[x];i;i=e1[i].next){
int v=e1[i].t;
if(!dfn[v]){
fa[v]=x;
tarjan(v); //tarjan 不是 dfs
size[x]++;
low[x]=min(low[v],low[x]);
if(low[v]>=dfn[x]&&fa[x]!=0) is[x]=1;//low [v] 不是low [x] !!!
}
else if(v!=fa[x]) low[x]=min(low[x],dfn[v]);
}
if(size[x]>1&&fa[x]==0) is[x]=1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: