NOIP模拟题 by天津南开中学 莫凡[tarjan][树剖][并查集]
来源:互联网 发布:视唱练耳软件 编辑:程序博客网 时间:2024/05/01 08:48
考试总结:
解题报告:
一. 图的连通性:
题意:给定一图,动态删边,动态求是否连通,且查询中输入的变量需xor当前边数才为最终输入数据;
分析:只删边则可以逆向建边用并查集查询是否连通,并查集基本上也是现阶段唯一一种可以在线快速求联通的算法了;
具体实现的话,先把边用康托展开转化为n+1进制的数,再用map去映射一个编号,然后两个mapy一个通过编号存储边出现次数,一个通过编号存储这条边的数便于反向查找;然后删边用map映射编号然后删map就可以了,最后反向连图加求联通;
程序:
#include<iostream>#include<cstdio>#include<map>#define ll long longusing namespace std;map<long long ,int>roa;const int maxn=150000+5;int mapy[maxn],n,m,t,sta,fin,fa[maxn],inde,tmp1[maxn];int tmp2[maxn],tmp3[maxn],ans[maxn];long long mapy2[maxn];ll calc(ll x,ll y,ll n){ return x*(n+1)+y;}int lookfor(int x){ if(fa[x]==x)return x; return fa[x]=lookfor(fa[x]);}void unionion(int x,int y){ x=lookfor(x);y=lookfor(y); fa[x]=y;}int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); scanf("%d %d %d",&n,&m,&t); for(int i=1;i<=m;i++){ scanf("%d %d",&sta,&fin); if(sta>fin)swap(sta,fin); if(!roa[calc(sta,fin,n)]){ roa[calc(sta,fin,n)]=++inde; mapy2[inde]=calc(sta,fin,n); } mapy[roa[calc(sta,fin,n)]]++; } for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=t;i++){ scanf("%d %d %d",&tmp1[i],&tmp2[i],&tmp3[i]); tmp2[i]^=m;tmp3[i]^=m;if(tmp2[i]>tmp3[i])swap(tmp2[i],tmp3[i]); if(tmp1[i]==1){ m--; mapy[roa[calc(tmp2[i],tmp3[i],n)]]--; } } for(int i=1;i<=inde;i++)if(mapy[i]){ unionion(mapy2[i]/(ll)(n+1),mapy2[i]%(ll)(n+1)); } for(int i=t;i>=1;i--){ if(tmp1[i]==1){ unionion(tmp2[i],tmp3[i]); } else { if(lookfor(tmp2[i])==lookfor(tmp3[i]))ans[i]=1; else ans[i]=0; } } for(int i=1;i<=t;i++)if(tmp1[i]==2)printf("%d\n",ans[i]); return 0;}
二. 树的连通性:
题意:给一棵树,动态查询是否相连,断边以及改变点的权值,点的权值在相连与否是会用,且输入变量必须xor上一次查询的答案才为真正的输入数据;
分析:暴力并查集可以直接怼过去……
标程:树链剖分;
Hzx: LCT O(nlogn)
类似于树链剖分的轻重链剖分,把整棵树用实边和虚边连接,实边部分是一条链,用Splay维护
然后删除就把实边变成虚边,并把虚边删掉。
暴力水过版,记得改父节点。
#include<iostream>#include<cstdio>#include<vector>using namespace std;const int maxn=2e5+5;int n,m,sta,fin,used[maxn],tmp1,tmp2,tmp3,lasten;int fa[maxn],dada[maxn],belonging[maxn];vector<int>e[maxn],sonn[maxn];void buildy(int u){ belonging[u]=1;used[u]=1; int len=e[u].size(); for(int i=0;i<len;i++)if(!used[e[u][i]]){ fa[e[u][i]]=u;sonn[u].push_back(e[u][i]); buildy(e[u][i]);}}void buildy2(int u){ int len=sonn[u].size(); for(int i=0;i<len;i++)if(fa[sonn[u][i]]==u){ belonging[sonn[u][i]]=belonging[u]; buildy2(sonn[u][i]); }}void cuty(int x,int y){ if(fa[x]==y){ belonging[x]=fa[x]=x;buildy2(x);} else if(fa[y]==x){ belonging[y]=fa[y]=y;buildy2(y);}}void ser(int x,int y){ if(belonging[x]==belonging[y]) printf("%d\n",lasten=dada[x]*dada[y]); else printf("%d\n",lasten=dada[x]+dada[y]);}int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&dada[i]); for(int i=1;i<n;i++){ scanf("%d %d",&sta,&fin); e[sta].push_back(fin); e[fin].push_back(sta); } buildy(1);belonging[1]=1; for(int i=1;i<=m;i++){ scanf("%d %d %d",&tmp1,&tmp2,&tmp3); tmp2^=lasten;tmp3^=lasten; if(tmp1==1)cuty(tmp2,tmp3); else if(tmp1==2)ser(tmp2,tmp3); else dada[tmp2]=tmp3; } return 0;}
认真写的树链剖分:
#include<iostream>#include<cstdio>using namespace std;const int maxn=2e5+5;int dep[maxn],fa[maxn],siz[maxn],son[maxn],top[maxn],w[maxn],fr[maxn],tov[maxn],des[maxn],val[maxn];int n,m,cnt,sta,fin,tmp1,tmp2,tmp3,lasten;struct node{ int lef,rig,dis;}a[maxn*4];void addedge(int sta,int fin){ tov[++cnt]=fr[sta];fr[sta]=cnt;des[cnt]=fin;}int dfs1(int u,int ste,int f){ dep[u]=ste;fa[u]=f; int maxn=0; for(int i=fr[u];i>0;i=tov[i]){ int tmp=dfs1(des[i],ste+1,u); if(maxn<tmp){ maxn=tmp;son[u]=des[i]; } siz[u]+=tmp; } return ++siz[u];}void dfs2(int u,int f){ w[u]=++cnt;top[u]=f; if(son[u])dfs2(son[u],f); for(int i=fr[u];i>0;i=tov[i]) if(des[i]!=son[u])dfs2(des[i],des[i]);}void build(int u,int lef,int rig){ int mid=(lef+rig)/2; a[u].lef=lef;a[u].rig=rig; if(lef!=rig) build(2*u,lef,mid),build(2*u+1,mid+1,rig);}void del(int u,int lef,int rig){ a[u].dis=1; int mid=(a[u].lef+a[u].rig)/2; if(a[u].lef==lef&&a[u].rig==rig)return; else if(lef>mid)del(2*u+1,lef,rig); else if(rig<=mid)del(2*u,lef,rig); else del(2*u,lef,mid),del(2*u+1,mid+1,rig);}int query(int u,int lef,int rig){ int mid=(a[u].lef+a[u].rig)/2; if(a[u].lef==lef&&a[u].rig==rig)return a[u].dis; else if(lef>mid)return query(2*u+1,lef,rig); else if(rig<=mid)return query(2*u,lef,rig); else return query(2*u,lef,mid)|query(2*u+1,mid+1,rig);}int queryctrl(int va,int vb){ int f1 = top[va], f2 = top[vb]; while (f1 != f2) { if (dep[f1] < dep[f2]) { swap(f1, f2); swap(va, vb); } if(query(1 ,w[f1], w[va]))return 1; va = fa[f1]; f1 = top[va]; } if (va == vb) return 0; if (dep[va] > dep[vb]) swap(va, vb); return query(1, w[son[va]], w[vb]); }int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&val[i]); for(int i=1;i<n;i++){ scanf("%d %d",&sta,&fin); if(sta>fin)swap(sta,fin); addedge(sta,fin); }cnt=0; dfs1(1,0,1);dfs2(1,1); build(1,1,n); for(int i=1;i<=m;i++){ scanf("%d %d %d",&tmp1,&tmp2,&tmp3); tmp2^=lasten;tmp3^=lasten; if(tmp1==1){ if(fa[tmp2]==tmp3)del(1,w[tmp2],w[tmp2]); else del(1,w[tmp3],w[tmp3]); } else if(tmp1==2){ if(queryctrl(tmp2,tmp3))printf("%d\n",lasten=val[tmp2]+val[tmp3]); else printf("%d\n",lasten=val[tmp2]*val[tmp3]); } else val[tmp2]=tmp3; } return 0;}
三. 逻辑的连通性:
题意:强连通分量模板题;
分析:同上;
#include<iostream>#include<cstdio>#include<vector>using namespace std;const int maxn=50005;int n,m,sta,fin,used[maxn],inde,inde2,low[maxn];int dfn[maxn],stack[maxn],instack[maxn],head;long long ans,roa[maxn];vector<int>e[maxn];void tarjan(int u){ used[u]=1;low[u]=dfn[u]=++inde; stack[++head]=u;instack[u]=1; int len=e[u].size(); for(int i=0;i<len;i++){ if(!used[e[u][i]]){ tarjan(e[u][i]); low[u]=min(low[u],low[e[u][i]]); } else if(instack[e[u][i]])low[u]=min(low[u],low[e[u][i]]); } if(dfn[u]==low[u]){ ++inde2; while(stack[head]!=u){ instack[stack[head]]=0;roa[inde2]++;head--; } instack[u]=0;roa[inde2]++;head--; }}int main(){ freopen("logic.in","r",stdin); freopen("logic.out","w",stdout); scanf("%d %d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d %d",&sta,&fin); e[sta].push_back(fin); } for(int i=1;i<=n;i++)if(!used[i]) tarjan(i); for(int i=1;i<=inde2;i++)ans+=roa[i]*(roa[i]-1LL)/2LL; printf("%I64d",ans); return 0;}
0 0
- NOIP模拟题 by天津南开中学 莫凡[tarjan][树剖][并查集]
- NOIP模拟题 2016.10.6 [并查集] [联通性] [Tarjan]
- NOIP模拟题 2016.10.31 [DP] [搜索] [并查集]
- NOIP模拟题[递推][并查集][DP]
- [NOIP模拟题][位运算][建模][并查集]
- [NOIP模拟] Road (并查集)
- [NOIP模拟][并查集]纸带
- NOIP 2016模拟赛[南开题]题解&总结
- noip 并查集
- [noip模拟赛]Formula 1(bfs+并查集)
- 【NOIp模拟】【二分图or并查集】GoToandPlay
- #NOIP模拟赛#字母选择Choose(并查集)
- NOIP模拟 做运动【并查集+最短路】
- [NOIP模拟][并查集][最短路]做运动
- NOIP模拟 纸带 【线段树】【并查集】
- 【NOIP 模拟题】刺杀大使(二分答案+并查集)
- 【NOIP模拟赛三】并查集+hash day2 third 雪后村庄(好题)
- 10.22 2017-57级模拟题 二分+并查集+MST+递推+DP+毒瘤noip
- Ubuntu下格式化U盘的方法(基于格式化命令)
- 自定义实现ListView左滑删除
- 动画的简单应用
- 关于字节的换算
- MITM(中间人攻击)原理及防范初探(一)
- NOIP模拟题 by天津南开中学 莫凡[tarjan][树剖][并查集]
- StuQ 发布的大数据工程师技能图谱(仅供参考)Big Data & Data Mining
- 【每天进步一点点】 Oracle如何导入带有约束关系的数据
- Java程序员应该知道的10个调试技巧
- 给 Android 开发者的 RxJava 详解
- 161012
- @ModelAttribute注解
- php字符串中双引号替换问题
- 在AS中使用Uiautomator