[游记]暑假集训4-2022.8.16
作者:互联网
今天还行?不过挂了 $85$ 分
A. 打地鼠
场切签到题
#include<cstdio> #include<cstring> #include<string> #include<queue> #define int long long #define WR WinterRain using namespace std; const int WR=3010,INF=1099588621776; int n,k; int dp[WR][WR]; int ans; int read(){ int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-'0'; ch=getchar(); } return s*w; } signed main(){ n=read(),k=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%1lld",&dp[i][j]); dp[i][j]+=dp[i][j-1]+dp[i-1][j]-dp[i-1][j-1]; } } for(int i=k;i<=n;i++){ for(int j=k;j<=n;j++){ ans=max(ans,dp[i][j]-dp[i-k][j]-dp[i][j-k]+dp[i-k][j-k]); } } printf("%lld\n",ans); return 0; }View Code
B. 竞赛图
首先这个数据范围是 $2^n$ 的;
然后我们考虑枚举每一个子图的出边,状态压缩地存储
显然对于一张图,我们可以割下一个节点,形成另外一张图
而新图的出边可以由子图和这个点的边按位与得来(后面有用)
也就是说图中必须每一个点都指向图外的一个点才存在这个图向这个点的连边
然后我们考虑如何计算答案,像是一个欧拉筛
首先如果一个图没有被打标记那么它是一个强连通分量
然后我们考虑这个强连通分量的出边,这些边显然都连接着点,设点的集合为 $T$
只考虑强连通分量和点集中的点,由于这些点没有连入强连通分量的边,因此这些点显然不能和强连通分量结合形成新的强连通分量
直接打标记就行了,复杂度是 $\Theta(2^n)$ 的
#include<cstdio> #include<cstring> #include<string> #include<stack> #define int long long #define WR WinterRain using namespace std; const int WR=17010000,INF=1099588621776; //tarjan显然不可行 //对着这2e8的数组陷入沉思 int n,edge[WR]; bool vis[WR]; int read(){ int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-'0'; ch=getchar(); } return s*w; } int lowbit(int x){ return x&(-x); } void binary(int x){ if(x>=2) binary(x/2); printf("%lld",x%2); } signed main(){ int t=read(); while(t--){ n=read();int ans=0; memset(edge,0,sizeof(edge)); edge[0]=(1<<n)-1; memset(vis,true,sizeof(vis)); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ int tmp=read(); if(tmp) edge[1<<(i-1)]|=(1<<(j-1)); } } for(int S=1;S<(1<<n);S++){ int S1=lowbit(S); edge[S]=(edge[S1]&edge[S^S1]); } for(int S=1;S<(1<<n);S++){ if(vis[S]){ // binary(edge[S]);printf("\n"); for(int i=edge[S];i;i=((i-1)&edge[S])){ // binary(i);printf(" ");binary(S);printf(" ");binary(S|i);printf("\n"); vis[S|i]=false; } } } for(int S=0;S<(1<<n);S++) if(vis[S]) ans++; printf("%lld\n",ans); } return 0; }View Code
C. 糖果
咕咕咕
D. 树
挂分:85
挂分原因:链顶的父亲不是 $top[fa[x]]$ !!!!!
这,如果做过 染色 这个树剖还是挺显然的
问题在于染色让维护的是点而这道题是边
不妨打上时间戳,如果一条边的两个端点时间戳不同那么它就是黑边,否则是白边
注意起始全为黑边
#include<cstdio> #include<cstring> #include<string> #include<queue> #define int long long #define WR WinterRain using namespace std; const int WR=300100,INF=1099588621776; struct Edge{ int pre,to; }; struct Tree{ int l,r,val,lzy; int lval,rval; Tree(){l=r=lzy=val=lval=rval=0;} }; struct SegmentTree{ Tree tree[WR<<3]; void pushup(int k){ tree[k].lval=tree[k<<1].lval,tree[k].rval=tree[k<<1|1].rval; tree[k].val=tree[k<<1].val+tree[k<<1|1].val; // printf("%lld %lld %lld %lld\n",tree[k<<1].val,tree[k<<1|1].val,tree[k<<1].rval,tree[k<<1|1].lval); if(tree[k<<1].rval!=tree[k<<1|1].lval) tree[k].val++; } void pushdown(int k){ // printf("%lld %lld\n",tree[k].l,tree[k].r); tree[k<<1].val=tree[k<<1|1].val=0; tree[k<<1].lzy=tree[k<<1|1].lzy=tree[k].lzy; tree[k<<1].lval=tree[k<<1].rval=tree[k].lzy; tree[k<<1|1].lval=tree[k<<1|1].rval=tree[k].lzy; tree[k].lzy=0; } void build(int k,int l,int r){ // printf("%lld %lld %lld\n",k,l,r); tree[k].l=l,tree[k].r=r; if(l==r){ tree[k].lval=tree[k].rval=l; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); pushup(k); } void modify(int k,int l,int r,int val){ if(tree[k].l>=l&&tree[k].r<=r){ // printf("%lld %lld %lld\n",tree[k].l,tree[k].r,val); tree[k].lval=tree[k].rval=val; tree[k].lzy=val;tree[k].val=0; return; } if(tree[k].lzy!=0) pushdown(k); int mid=(tree[k].l+tree[k].r)>>1; if(l<=mid) modify(k<<1,l,r,val); if(r>mid) modify(k<<1|1,l,r,val); pushup(k); } int query(int k,int l,int r){ // printf("%lld %lld %lld %lld\n",k,l,r,tree[k].lzy); if(tree[k].l>=l&&tree[k].r<=r){ return tree[k].val; } if(tree[k].lzy!=0) pushdown(k); int mid=(tree[k].l+tree[k].r)>>1,res=0; if(r<=mid) return query(k<<1,l,r); if(l>mid) return query(k<<1|1,l,r); res=query(k<<1,l,r)+query(k<<1|1,l,r); if(tree[k<<1].rval!=tree[k<<1|1].lval) res++; return res; } int getcolor(int k,int pos){ if(tree[k].l==tree[k].r){ return tree[k].lval; } if(tree[k].lzy!=0) pushdown(k); int mid=(tree[k].l+tree[k].r)>>1; if(pos<=mid) return getcolor(k<<1,pos); else return getcolor(k<<1|1,pos); } }segment; struct Tree_Cut{ Edge edge[WR<<1]; int head[WR],tot=0; int fa[WR],son[WR],sze[WR],dpt[WR]; int ipt[WR],rnk[WR],top[WR],cnt; void add(int u,int v){ edge[++tot].pre=head[u]; edge[tot].to=v; head[u]=tot; } void dfs1(int u,int root){ dpt[u]=dpt[root]+1;fa[u]=root; sze[u]=1; for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to; if(v==root) continue; dfs1(v,u); sze[u]+=sze[v]; if(sze[v]>sze[son[u]]) son[u]=v; } } void dfs2(int u,int tp){ top[u]=tp,ipt[u]=++cnt,rnk[cnt]=u; if(son[u]) dfs2(son[u],tp); for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void path_modify(int x,int y,int val){ // printf("%lld\n",val); while(top[x]!=top[y]){ if(dpt[top[x]]<dpt[top[y]]) swap(x,y); // printf("%lld %lld\n",ipt[top[x]],ipt[x]); segment.modify(1,ipt[top[x]],ipt[x],val); x=fa[top[x]]; } if(ipt[x]>ipt[y]) swap(x,y); segment.modify(1,ipt[x],ipt[y],val); } int path_query(int x,int y){ int res=0; while(top[x]!=top[y]){ // printf("%lld %lld\n",ipt[top[x]],ipt[top[y]]); if(dpt[top[x]]<dpt[top[y]]) swap(x,y); // printf("%lld %lld\n",ipt[top[x]],ipt[x]); res+=segment.query(1,ipt[top[x]],ipt[x]); if(segment.getcolor(1,ipt[top[x]])!=segment.getcolor(1,ipt[fa[top[x]]])) res++; x=fa[top[x]]; } if(ipt[x]>ipt[y]) swap(x,y); res+=segment.query(1,ipt[x],ipt[y]); return res; } }tree; int n,q; int read(){ int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-'0'; ch=getchar(); } return s*w; } signed main(){ n=read();int tag=0; for(int i=1;i<n;i++){ int u=read(),v=read(); tree.add(u,v);tree.add(v,u); } tree.dfs1(1,0);tree.dfs2(1,1); segment.build(1,1,n); // for(int i=1;i<=n;i++) printf("%lld ",tree.dpt[i]); // for(int i=1;i<(n<<1);i++) printf("%lld %lld %lld\n",segment.tree[i].l,segment.tree[i].r,segment.tree[i].val); q=read(); while(q--){ int opt=read(); if(opt==1){ int x=read(),y=read(); tag--; tree.path_modify(x,y,tag); // for(int i=1;i<(n<<1);i++) printf("%lld %lld %lld\n",segment.tree[i].l,segment.tree[i].r,segment.tree[i].val); }else{ // printf("I am here\n"); int x=read(),y=read(); printf("%lld\n",tree.path_query(x,y)); } } return 0; }View Code
标签:ch,ipt,16,int,top,WR,2022.8,include,集训 来源: https://www.cnblogs.com/WintersRain/p/16592845.html