专项测试(图论1)
专项测试(图论1)
第一题是分块,没有想到,第二题暴力,没有对拍,第三题网络流,我人傻了
越来越难哈,到现在了啥也不会,啥也不是。
关于我网络流学了像没学一样,所以我打算多做一点网络流的题。。
T1 序列
直接分块维护,不会线段树
每个块维护一个偏移量,最小值,变化次数的差分数组
每次加的时候直接加就行,取最大值的是候\(lower_bound\)一下
分块有一个小问题,注意最右边的一块,循环的时候别忘了卡个边界
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int N=2e5+5;
int n,m;
int mn[N],cf[N],ad[N],zc[N];
struct node{
int v,id,ci;
bool operator < (node a)const{
return v<a.v;
}
}a[N];
int bl[N],sq;
void dow(int x){
fo(i,(x-1)*sq+2,x*sq)cf[i]+=cf[i-1];
fo(i,(x-1)*sq+1,x*sq)a[i].ci+=cf[i]+zc[x],cf[i]=0;
fo(i,(x-1)*sq+1,x*sq)a[i].v=a[i].v+ad[x]>mn[x]?a[i].v+ad[x]:mn[x];
ad[x]=zc[x]=0;
}
void add(int x,int y,int z){
if(!z)return ;
dow(bl[x]);
fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id>=x&&a[i].id<=y)a[i].v+=z,a[i].ci++;
sort(a+(bl[x]-1)*sq+1,a+bl[x]*sq+1);mn[bl[x]]=a[(bl[x]-1)*sq+1].v;
fo(i,bl[x]+1,bl[y]-1)ad[i]+=z,zc[i]++,mn[i]+=z;
if(bl[x]!=bl[y]){
dow(bl[y]);
fo(i,(bl[y]-1)*sq+1,bl[y]*sq)if(a[i].id>=x&&a[i].id<=y)a[i].v+=z,a[i].ci++;
sort(a+(bl[y]-1)*sq+1,a+bl[y]*sq+1);mn[bl[y]]=a[(bl[y]-1)*sq+1].v;
}
}
void pmx(int x,int y,int z){
dow(bl[x]);
fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id>=x&&a[i].id<=y&&a[i].v<z)a[i].v=z,a[i].ci++;
sort(a+(bl[x]-1)*sq+1,a+bl[x]*sq+1);mn[bl[x]]=a[(bl[x]-1)*sq+1].v;
fo(i,bl[x]+1,bl[y]-1){
if(mn[i]>=z)continue;
mn[i]=z;int pos=lower_bound(a+(i-1)*sq+1,a+i*sq+1,node{z-ad[i],0})-a;
cf[(i-1)*sq+1]++;if(pos<=i*sq)cf[pos]--;
}
if(bl[x]!=bl[y]){
dow(bl[y]);
fo(i,(bl[y]-1)*sq+1,bl[y]*sq)if(a[i].id>=x&&a[i].id<=y&&a[i].v<z)a[i].v=z,a[i].ci++;
sort(a+(bl[y]-1)*sq+1,a+bl[y]*sq+1);mn[bl[y]]=a[(bl[y]-1)*sq+1].v;
}
}
void query(int x){
dow(bl[x]);
fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id==x)printf("%lld %lld\n",a[i].v,a[i].ci);
}
signed main(){
n=read();sq=sqrt(n);
fo(i,1,n)a[i].v=read(),a[i].id=i;
fo(i,1,n)bl[i]=(i-1)/sq+1;
fo(i,1,(n-1)/sq+1){
sort(a+(i-1)*sq+1,a+i*sq+1);
mn[i]=a[(i-1)*sq+1].v;
}
m=read();
while(m--){
char tp[5];scanf("%s",tp+1);
int x=read(),y,z;
if(tp[1]=='A'){
y=read();z=read();
add(x,y,z);
}
if(tp[1]=='M'){
y=read();z=read();
pmx(x,y,z);
}
if(tp[1]=='Q')query(x);
}
}
T2 旅行计划
奇数的时候全是\(0\),因为可以在某一条路径上走\(K\)遍
偶数的时候发现之和路径的奇偶性有关,于是就切了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int N=1e5+5;
int n,m,q;
int to[N*2],nxt[N*2],val[N*2],head[N],rp;
void add_edg(int x,int y,int z){
to[++rp]=y;val[rp]=z;
nxt[rp]=head[x];head[x]=rp;
}
int fai[N],gd[N];
int find(int x){return fai[x]==x?x:fai[x]=find(fai[x]);}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int dis[N][2];
void dfs(int x,int t,int g){
if(dis[x][t])return ;dis[x][t]=1;
for(int i=head[x];i;i=nxt[i])dfs(to[i],t^((val[i]/g)&1),g);
}
signed main(){
n=read();m=read();q=read();
fo(i,1,n)fai[i]=i;
fo(i,1,m){
int u=read(),v=read(),w=read();
add_edg(u,v,w);add_edg(v,u,w);
int fx=find(u),fy=find(v);
if(fx!=fy)fai[fx]=fy,gd[fy]=gcd(gd[fy],gd[fx]);
gd[fy]=gcd(gd[fy],w);
}
fo(i,1,n)if(fai[i]==i)dfs(i,0,gd[i]);
fo(i,1,q){
int x=read(),y=read(),k=read();
if(find(x)!=find(y)){printf("NIE\n");continue;}
bool fl=false;int nw=k,mw=gd[find(x)]*2,gu=gcd(gd[find(x)]*2,k);
while(!(nw&1)){
nw>>=1;mw>>=1;
if(mw&1){fl=true;break;}
}
// cerr<<nw<<" "<<mw<<" "<<fl<<endl;
if(!fl){printf("0\n");continue;}
// cerr<<"gu"<<" "<<gu<<endl;
fl=((dis[x][1]&&dis[y][1])||(dis[x][0]&&dis[y][0]));
if(!fl)printf("%lld\n",gu/2);
else printf("0\n");
}
return 0;
}
T3 Hack
确实是一眼就知道是最小割,但是不知道咋建图
于是题解告诉我要把反边全部建成\(inf\)
仔细理解了一下,发现这样建图的话,横叉边是可以不断退流的
所以一个横叉边链接的路径必须在同一侧割掉,于是我们就完美的避免了统一路径上有两个割边的情况
由于每个边都有可能作为横叉边,所以我们就干脆都把反边设成\(inf\)
于是乎,\(WA\)成\(70pts\),怎么回事??发现如果有一个点向\(s\)有连边,\(t\)向它有连边,那么你就完蛋了,因为你必须要把\(inf\)割掉
于是我们要预先判断一个点是否能被\(s\)到达,并且是否可以到达\(t\)
哦对了,还有如果\(1\)和\(n\)在一个强连通分量里,那是不行的,无解
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=105;
const int M=2505;
int n,m,s,t;
struct D{int x,y,v;}d[M];
struct E{int to,nxt,val;}e[M*2];
int head[N],hea[N],rp;
void add_edg(int x,int y,int w){
e[++rp].to=y;e[rp].val=w;
e[rp].nxt=head[x];head[x]=rp;
}
int dfn[N],low[N],cnt;
int bl[N],col,sta[N],top;
void tarjan(int x){
low[x]=dfn[x]=++cnt;
sta[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y])tarjan(y),low[x]=min(low[x],low[y]);
else if(!bl[y])low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
bl[x]=++col;
while(sta[top]!=x)bl[sta[top]]=col,top--;
top--;
}
}
int dis[N];
bool bfs(){
memset(dis,0x3f,sizeof(dis));
memcpy(head,hea,sizeof(hea));
queue<int> q;while(!q.empty())q.pop();
q.push(s);dis[s]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!e[i].val||dis[y]<=dis[x]+1)continue;
dis[y]=dis[x]+1;q.push(y);
if(y==t)return true;
}
}
return false;
}
int dfs(int x,int in){
if(x==t)return in;
int rest=in,go=0;
for(int i=head[x];i;head[x]=i=e[i].nxt){
int y=e[i].to;
if(!e[i].val||dis[y]!=dis[x]+1)continue;
go=dfs(y,min(rest,e[i].val));
if(go)e[i].val-=go,e[i^1].val+=go,rest-=go;
else dis[y]=0;
if(!rest)break;
}
return in-rest;
}
int dinic(){
int ret=0;
memcpy(hea,head,sizeof(head));
while(bfs())ret+=dfs(s,inf);
return ret;
}
bool vis[N],via[N];
bool pd(int x){
if(x==bl[n])return true;
if(via[x])return vis[x];
via[x]=true;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
vis[x]|=pd(y);
}
return vis[x];
}
signed main(){
n=read();m=read();s=1;t=n;
fo(i,1,m){
d[i].x=read()+1;d[i].y=read()+1;d[i].v=read();
add_edg(d[i].x,d[i].y,0);
}
fo(i,1,n)if(!dfn[i])tarjan(i);
memset(head,0,sizeof(head));rp=1;
fo(i,1,m){
if(bl[d[i].x]==bl[d[i].y])continue;
add_edg(bl[d[i].x],bl[d[i].y],0);
}
pd(bl[1]);vis[bl[1]]=vis[bl[n]]=true;
if(bl[1]==bl[n]){printf("-1");return 0;}
memset(head,0,sizeof(head));rp=1;
fo(i,1,m){
if(!vis[bl[d[i].x]]||!vis[bl[d[i].y]])continue;
add_edg(d[i].x,d[i].y,d[i].v);
add_edg(d[i].y,d[i].x,inf);
}
printf("%lld",dinic());
}
QQ:2953174821