1:并查集
P3183食物链
#define man 300050 int fa[man],opt,x,y,fx,fy,n,k,ans=0; int find(int x){ if(fa[x]==x) return fa[x]; return fa[x]=find(fa[x]); } int main(){ n=read();k=read(); for(rint i=1;i<=3*n;i++) fa[i]=i; //[1,n]同类;[n+1,2*n]猎物;[2*n+1,3*n]天敌; for(rint i=1;i<=k;i++){ opt=read();x=read();y=read(); if(x>n||y>n){ ans++;continue;} if(opt==1){ if(find(x+n)==find(y)||find(x+n+n)==find(y)){ ans++;continue;} //y是x的猎物或者天敌,谎言 fa[find(x)]=find(y);//x的同类是y的同类 fa[find(x+n)]=find(y+n);//x的猎物是y的猎物 fa[find(x+n+n)]=find(y+n+n);//x的天敌是y的天敌 } else if(opt==2){ if(find(x)==find(y)||find(x+n+n)==find(y)){ ans++;continue;} //x是y的同类或者y是x的天敌,谎言 fa[find(x)]=find(y+n+n);//y的天敌是x fa[find(x+n)]=find(y);//x的猎物是y fa[find(x+n+n)]=find(y+n);//x的天敌是y的猎物(由循环关系可得) } } cout<<ans<<endl; return 0; }
2.单调队列
P1638逛画展
int n,m; int pos[2050];//第i个画师的最后出现的下标 int pic[1000050];//画作 int cnt,l=1;//已经出现的画师的数量及不断更新的左端点 int ml=0,mr=0,ans=1e9+7;//最终答案的左右端点及区间的长度 int main(){ n=read();m=read(); memset(pos,0,sizeof(pos)); for(rint i=1;i<=n;i++){ pic[i]=read(); if(!pos[pic[i]]) cnt++;//如果之前的画师没有出现过,那么cnt+1 pos[pic[i]]=i;//将画师的下标更新到最新的一幅 while(l!=i && l<pos[pic[l]]) l++;//如果最左边的画师的作品在后面的枚举中出现过,那么就可以向后移动一个 if(cnt==m && i-l+1<ans)//如果数量足够并且区间的长度更有,那么更新 ml=l,mr=i,ans=i-l+1; } cout<<ml<<" "<<mr<<endl; return 0; }
3.差分约束
求最小值时用最长路,求最大值是用最短路
P3275 [SCOI2011]糖果
#define man 1000050 int n,m; struct edge{ int next,to,dis;}e[man]; int head[man<<1],num=0; inline void add(int from,int to,int dis){ e[++num]=(edge){head[from],to,dis}; head[from]=num; } int dis[man],vis[man],cnt[man]; inline void spfa(int s){ queue<int>q; memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); //memset(cnt,0,sizeof(cnt)); dis[s]=0;vis[s]=0;q.push(s); do{ int u=q.front();q.pop();vis[u]=0;cnt[u]++; if(cnt[u]>n){ printf("-1 ");exit(0);} for(rint i=head[u];i;i=e[i].next){ int to=e[i].to; if(dis[to]<dis[u]+e[i].dis){ dis[to]=dis[u]+e[i].dis; if(!vis[to]){ vis[to]=1; q.push(to); } } } }while(q.size()); } int main(){ //printf("%.3lf M ",(double)sizeof(e)/(1<<20)); n=read();m=read(); for(rint i=1,opt,x,y;i<=m;i++){ opt=read();x=read();y=read(); if(opt==1) add(x,y,0),add(y,x,0); if(opt==2) add(x,y,1); if(opt==3) add(y,x,0); if(opt==4) add(y,x,1); if(opt==5) add(x,y,0); if(opt%2==0&&x==y){ printf("-1 "); return 0; } } for(rint i=n;i>=1;i--) add(0,i,1); spfa(0); long long ans=0; for(rint i=1;i<=n;i++){ ans+=dis[i]; } printf("%lld ",ans); return 0; }
4.二分图匹配
P2055 假期的宿舍
#define man 55 int T,n; int a[man],b[man],c[man][man],tot,ans; int used[man],link[man]; bool find(int s){ for(rint i=1;i<=n;i++){ if(a[i]==1) if(c[s][i]==1&&used[i]==0){ used[i]=1; if(link[i]==0||find(link[i])){ link[i]=s; return 1; } } } return 0; } int main(){ T=read(); while(T--){ n=read(); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(link,0,sizeof(link)); for(rint i=1;i<=n;i++) a[i]=read(); for(rint i=1;i<=n;i++) b[i]=read(); for(rint i=1,x;i<=n;i++) for(rint j=1;j<=n;j++){ x=read(); if(x==1||i==j) c[i][j]=1; } ans=0,tot=0; for(rint i=1;i<=n;i++){ memset(used,0,sizeof(used)); if(a[i]==0||(a[i]==1&&b[i]==0)){ tot++; if(find(i)) ans++; } } if(ans==tot) printf("^_^ "); else printf("T_T "); } return 0; }