标签:include int 29 sze ch edge WR 2022.7 学长
为大家激情上演爆零秀!T3 和 T4 全写的是正解,并且得到学长的认可
T3 因为哈希冲突挂了,T4 更加奇妙,因为连通块的 $id$ 没加爆了个零
挂了 $200$ 分,最后得分 $100/400$
真的,以后再用哈希我是狗
开心 ^_^
A. ^_^
B. 软件包管理器
C. 地理课
D. 道路和航线
A.^_^
一开始看到期望吓得直接跳了
于是到比赛结束也没看题
结果 $\cdots\cdots$
#include<cstdio> #include<cstring> #include<string> #include<vector> #include<unordered_map> #define WR WinterRain #define int long long using namespace std; const int WR=1001000,INF=2147483647,mod=998244353; int n; int a[WR],ny[WR],sze[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<<3)+(s<<1)+ch-'0'; ch=getchar(); } return s*w; } int quick_pow(int a,int b){ int base=a,res=1; while(b){ if(b&1) res=res*base%mod; base=base*base%mod; b>>=1; } return res; } signed main(){ n=read(); ny[0]=ny[1]=1; for(int i=2;i<=n;i++){ ny[i]=(mod-mod/i)*ny[mod%i]%mod; } for(int i=1;i<=n-1;i++){ a[i]=read(); } for(int i=n-1;i>=1;i--){ sze[i+1]+=1; sze[a[i]]+=sze[i+1]; } sze[1]+=1; for(int i=1;i<=n;i++){ ans=(ans+ny[sze[i]])%mod; } printf("%lld\n",ans); return 0; }View Code
B. 软件包管理器
看到这种东西显然树剖
显然地用一棵线段树维护
更加显然地,统计答案时顺便修改即可
真的很模板,不想说更多了 $\cdots$
#include<cstdio> #include<cstring> #include<string> #define WR WinterRain #define int long long using namespace std; const int WR=1001000,INF=2147483647,mod=1e9+7; struct SegmentTree{ int l,r,val,lzy; }tree[WR]; struct Edge{ int pre,to; }edge[WR]; int n,q; int head[WR],tot; int fa[WR],dpt[WR],son[WR],sze[WR]; int top[WR],ipt[WR],rnk[WR],cnt=0; 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<<3)+(s<<1)+ch-'0'; ch=getchar(); } return s*w; } void add(int u,int v){ edge[++tot].pre=head[u]; edge[tot].to=v; head[u]=tot; } void pushup(int k){ tree[k].val=tree[k<<1].val+tree[k<<1|1].val; } void pushdown(int k){ tree[k<<1].lzy=tree[k].lzy; tree[k<<1|1].lzy=tree[k].lzy; tree[k].lzy--; tree[k<<1].val=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].lzy; tree[k<<1|1].val=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].lzy; tree[k].lzy=0; } void build(int k,int l,int r){ tree[k].l=l,tree[k].r=r; if(l==r){ tree[k].val=0; 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 st,int ed,int val){ if(tree[k].l>=st&&tree[k].r<=ed){ tree[k].lzy=val+1; tree[k].val=(tree[k].r-tree[k].l+1)*val; return; } if(tree[k].lzy) pushdown(k); int mid=(tree[k].l+tree[k].r)>>1; if(st<=mid) modify(k<<1,st,ed,val); if(ed>mid) modify(k<<1|1,st,ed,val); pushup(k); } int query(int k,int l,int r){ //printf("%lld %lld %lld %lld\n",tree[k].l,tree[k].r,l,r); if(tree[k].l>=l&&tree[k].r<=r){ return tree[k].val; } if(tree[k].lzy) pushdown(k); int mid=(tree[k].l+tree[k].r)>>1,res=0; if(l<=mid) res+=query(k<<1,l,r); if(r>mid) res+=query(k<<1|1,l,r); return res; } void dfs1(int u,int root){ //printf("%lld %lld\n",u,root); fa[u]=root,dpt[u]=dpt[root]+1,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){ while(top[x]!=top[y]){ if(dpt[top[x]]<dpt[top[y]]) swap(x,y); modify(1,ipt[top[x]],ipt[x],val); x=fa[top[x]]; } if(dpt[x]>dpt[y]) swap(x,y); modify(1,ipt[x],ipt[y],val); } int path_query(int x,int y){ int res=0; //printf("%lld %lld\n",top[x],top[y]); while(top[x]!=top[y]){ if(dpt[top[x]]<dpt[top[y]]) swap(x,y); res+=query(1,ipt[top[x]],ipt[x]); x=fa[top[x]]; } if(dpt[x]>dpt[y]) swap(x,y); res+=query(1,ipt[x],ipt[y]); return res; } signed main(){ n=read(); for(int i=1;i<n;i++){ int fa=read(); add(fa+1,i+1); } build(1,1,n); dfs1(1,0);dfs2(1,1); //for(int i=1;i<=n;i++) printf("%lld ",dpt[i]); q=read(); while(q--){ char str[10]; scanf("%s",str+1); if(str[1]=='i'){ int x=read()+1; //printf("%lld\n",dpt[x]); printf("%lld\n",dpt[x]-path_query(1,x)); path_modify(1,x,1); }else{ int x=read()+1; printf("%lld\n",query(1,ipt[x],ipt[x]+sze[x]-1)); modify(1,ipt[x],ipt[x]+sze[x]-1,0); } } return 0; }View Code
C. 地理课
这,我再也不用哈希了TAT
赛时本来有 $80$ 分,结果哈希冲突挂到 $0$ 分
考虑建立一棵以时间为节点的线段树,统计出每条边存在的时间段
可以用 $\operatorname{map}$ 进行一个映射方便地统计出边存在的起始时间和终止时间
不妨设当前时间答案为 $pos$,连通块大小为 $sze$
合并操作不难想到,设两个连通块为 $u$ 和 $v$,只用让 $pos=\dfrac{pos\times (sze[u]+sze[v])}{sze[u]\times sze[v]}$ 即可
此时可以让 $u$ 合并进 $v$ ,删除 $u$ ,这里需要用到并查集
但是我们还要把连通块分裂开,这时我们需要访问历史版本
然后考虑启发式合并,维护一个叫做 $bin$ 的 $\operatorname{vector}$ ,里面有 $4$ 个元素 $id,u,v,szeu$
表示在线段树的第 $k$ 个结点处,$u$ 被合并进了 $v$,$u$ 的大小为 $szeu$
只需要让 $sze[u]=szeu , fa[u]=u , sze[v]=sze[v]-sze[u]$ 即可
此时 $pos=\dfrac{pos\times sze[u] \times sze[v]}{sze[u]+sze[v]}$
注意,由于我们要访问历史版本,不能对并查集进行路径压缩!!!
还要注意时间,如果当前 $bin$ 中元素的 $id$ 值不等于 $k$ 那么不执行操作
然后就差不多做完了
#include<cstdio> #include<cstring> #include<string> #include<vector> #include<unordered_map> #define WR WinterRain #define int long long using namespace std; const int WR=1001000,INF=2147483647,mod=1e9+7; struct Edge{ int u,v,st,ed; }edge[WR]; struct SegmentTree{ int l,r; vector<int>road; }tree[WR]; struct Bin{ int id,u,v,szeu; }; struct PairHash{ public: template<typename T,typename U> size_t operator()(const pair<T,U> &x) const{ return hash<T>()(x.first)^hash<U>()(x.second); } }; int n,m; int pos; int fa[WR],sze[WR]; int ny[WR],ans[WR]; int hsh[WR<<2]; vector<Bin>bin; unordered_map<pair<int,int>,int,PairHash>mp; 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<<3)+(s<<1)+ch-'0'; ch=getchar(); } return s*w; } int quick_pow(int a,int b){ int base=a,res=1; while(b){ if(b&1) res=res*base%mod; base=base*base%mod; b>>=1; } return res; } int getfa(int x){ if(fa[x]==x) return x; return getfa(fa[x]); } void build(int k,int l,int r){ tree[k].l=l,tree[k].r=r; if(l==r){ return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void modify(int k,int l,int r,int val){ if(tree[k].l>=l&&tree[k].r<=r){ tree[k].road.push_back(val); return; } 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); } void block_split(int k){ if(bin.empty()) return; for(int i=bin.size()-1;i>=0;i--){ if(bin[i].id!=k) return; pos=pos*ny[sze[bin[i].v]]%mod; fa[bin[i].u]=bin[i].u,sze[bin[i].u]=bin[i].szeu; sze[bin[i].v]-=sze[bin[i].u]; pos=pos*sze[bin[i].u]%mod*sze[bin[i].v]%mod; bin.pop_back(); } } void block_merge(int k){ for(int i=0;i<tree[k].road.size();i++){ int tmp=tree[k].road[i]; int fau=getfa(edge[tmp].u),fav=getfa(edge[tmp].v); if(fau!=fav){ //printf("Hey\n"); pos=pos*ny[sze[fau]]%mod*ny[sze[fav]]%mod; pos=pos*((sze[fau]+sze[fav])%mod)%mod; if(sze[fau]>=sze[fav]) swap(fau,fav); bin.push_back(Bin{k,fau,fav,sze[fau]}); fa[fau]=fav,sze[fav]+=sze[fau],sze[fau]=0; } } } void get_ans(int k){ block_merge(k); if(tree[k].l==tree[k].r){ ans[tree[k].l]=pos; block_split(k); return; } get_ans(k<<1); get_ans(k<<1|1); block_split(k); } signed main(){ n=read(),m=read(); for(int i=1;i<=n;i++) sze[i]=1,fa[i]=i; ny[0]=1; for(int i=1;i<=n*2;i++) ny[i]=quick_pow(i,mod-2); for(int i=1;i<=m;i++){ int opt=read(); edge[i].u=read(),edge[i].v=read(); if(edge[i].u>edge[i].v) swap(edge[i].u,edge[i].v); //printf("%lld %lld\n",edge[i].u,edge[i].v); //printf("%lld %lld\n",tmp,hsh[tmp]); if(opt==1) mp[make_pair(edge[i].u,edge[i].v)]=i,edge[i].st=i; else edge[mp[make_pair(edge[i].u,edge[i].v)]].ed=i-1; } build(1,1,m); for(int i=1;i<=m;i++){ if(!edge[i].ed) edge[i].ed=m; if(edge[i].st&&edge[i].ed){ modify(1,edge[i].st,edge[i].ed,i); } } pos=1; get_ans(1); for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }View Code
D. 道路和航线
首先啥都别说,直接大喊:关于SPFA,它死了
(其实并没有死干净,随机化的 $\operatorname{SPFA}$ 是可以过的)
既然$\operatorname{SPFA}$ 死了我们只能考虑魔改 $\operatorname{Dijkstra}$
发现图中保证不会有负环,所以大胆改
首先在输入飞机边之前对图进行一遍 $\operatorname{DFS}$ 找出连通块
然后对于飞机边,统计连通块的入度
进行一个拓扑排序,如果当前连通块入度是 $0$ 那么对整个块进行 $\operatorname{Dijkstra}$ 统计最短路
如果在 $\operatorname{Dijkstra}$ 里发现了存在的连向其它连通块的边,让那个连通块的入度减一
如果有入度为 $0$ 的,接着入队
由于负权边的存在,到达不了的点可能被负权边更新,因此对于 $INF$ 的判断要注意一下下
关于我的挂分:可以发现第 $126$ 行中有一个 $ipt[blng[v]]++$ 统计入度
那么我赛时写的什么呢?$ipt[v]++$
我好开心啊诶嘿嘿啊哇嘎嘎嘎`~*呜?#呼&=8呼!&/哈*&()#!%哈#^*^%@#^哈#$%@#@$[已损坏]
//关于SPFA: // · 它死了 #include<cstdio> #include<cstring> #include<string> #include<stack> #include<queue> #define WR WinterRain #define int long long using namespace std; const int WR=1001000,INF=1099588621776,mod=1e9+7; struct Edge{ int pre,to,val; }edge[WR]; int t,r,p,S; int head[WR],tot; // int dfn[WR],low[WR],cnt; // bool instk[WR]; // stack<int>s; int blng[WR],point; int ipt[WR],dis[WR]; bool vis[WR]; queue<int>topo; priority_queue<pair<int,int> >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<<3)+(s<<1)+ch-'0'; ch=getchar(); } return s*w; } void add(int u,int v,int val){ edge[++tot].pre=head[u]; edge[tot].to=v; edge[tot].val=val; head[u]=tot; } // void tarjan(int u){ // ipt[u]=low[u]=++cnt; // s.push(u),instk[u]=true; // for(int i=head[u];i;i=edge[i].pre){ // int v=edge[i].to; // if(!ipt[v]){ // tarjan(v); // low[u]=min(low[u],low[v]); // }else if(instk[v]){ // low[u]=min(low[u],ipt[v]); // } // } // if(low[u]==ipt[u]){ // int v; // point++; // do{ // v=s.top(),s.pop(); // instk[v]=false; // sze[point]++; // blng[v]=point; // }while(v!=u); // } // } //等等我该怎么求最短路??? //Wait how could I found the shortest path? //这,好像有点尴尬,不会tarjan是假的吧 //Oh that is embarrassing,Tarjan is unavaliable to this problem //------------------------------- //好像真的假了,我不会求最短路T_T //It is fake,'cause I can not solve the shortest path T_T void tarjan(int u){//However this does not looks like tarjan for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to; if(!blng[v]){//But as I have to found the belong of u blng[v]=point; tarjan(v);//I'd better name it tarjan :P } }//Oh,I is a really English men } void dijkstra(){ while(!q.empty()){ int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to,val=edge[i].val; //printf("%lld %lld\n",blng[u],blng[v]); if(dis[v]>dis[u]+edge[i].val){ //printf("%lld %lld %lld\n",dis[u],dis[v],val); dis[v]=dis[u]+val; //if(vis[v]) continue; if(blng[u]==blng[v]){ q.push(make_pair(-dis[v],v)); //vis[v]=true; } } if(blng[u]!=blng[v]&&--ipt[blng[v]]==0){ //printf("%lld\n",blng[v]); topo.push(blng[v]); } } } } signed main(){ t=read(),r=read(),p=read(),S=read(); for(int i=1;i<=r;i++){ int u=read(),v=read(),val=read(); add(u,v,val);add(v,u,val); } for(int i=1;i<=t;i++){ dis[i]=INF; if(!blng[i]){ blng[i]=++point; tarjan(i); } } dis[S]=0; // for(int i=1;i<=t;i++) printf("%lld ",blng[i]); for(int i=1;i<=p;i++){ int u=read(),v=read(),val=read(); add(u,v,val); ipt[blng[v]]++; } for(int i=1;i<=point;i++){ if(!ipt[i]) topo.push(i); } while(!topo.empty()){ int id=topo.front(); topo.pop(); //printf("%lld\n",id); for(int i=1;i<=t;i++){ if(blng[i]==id) q.push(make_pair(-dis[i],i)); } dijkstra(); } for(int i=1;i<=t;i++){ if(dis[i]>INF/2) printf("NO PATH\n"); else printf("%lld\n",dis[i]); } return 0; }View Code
标签:include,int,29,sze,ch,edge,WR,2022.7,学长 来源: https://www.cnblogs.com/WintersRain/p/16533561.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。