Noip模拟17 2021.7.16
我愿称这场考试为STL专练
T1 世界线
巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的。
但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但是也有很大代价
相比bool是好的,所以这题要用一个节点池来存放节点卡内存限制
但是当时考试的时候还不知道有这种东西。。
考试时候的想法是:
因为发现如果暴力的话只用$floyd$循环找一遍无法将所有边找全,于是想到使用多次$floyd$
记一个ans数组记录每一次新产生的连边,如果这一次的ans为0,直接break,然后把ans数组加和输出
因为有大样例,发现跑6次刚刚好
数据范围较小,水五十是可以的
然后说说正解。使用拓扑序思想
因为有多个联通块,则应该找到所有图进行dfs。
使用bitset记录每一个点的子节点可能产生的贡献,将其存到一个进制数中,知道子节点的贡献为0,将其回收
新技巧:
1.内存池回收;
2.$bitset$各种使用方法
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int read(){ 4 int x=0,f=1; char ch=getchar(); 5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 7 return x*f; 8 } 9 const int NN=6e4+5,MM=1e5+5; 10 int n,m,in[NN],ot[NN],tot; 11 struct SNOW{int to,next;}; SNOW e[MM]; int head[NN],rp; 12 inline void add(int x,int y){e[++rp]=(SNOW){y,head[x]}; head[x]=rp;} 13 bitset<60001> s[30001]; 14 int id[NN],ans,bin[NN],top; 15 bool vis[NN]; 16 inline void calc(int x){ 17 ans+=s[id[x]].count()-1-ot[x]; 18 s[bin[++top]=id[x]].reset(); 19 } 20 inline int New(){ 21 if(top) return bin[top--]; 22 return ++tot; 23 } 24 inline void dfs(int x){ 25 vis[x]=true; 26 if(!id[x]) id[x]=New(); 27 s[id[x]].set(x); 28 for(int i=head[x];i;i=e[i].next){ 29 int y=e[i].to; 30 if(vis[y]){ 31 if(!id[y]) id[y]=New(); 32 s[id[x]]|=s[id[y]]; 33 in[y]--; 34 if(!in[y]) calc(y); 35 continue; 36 } 37 if(!id[y]) id[y]=New(); 38 dfs(y); 39 s[id[x]]|=s[id[y]]; 40 in[y]--; 41 if(!in[y]) calc(y); 42 } 43 } 44 namespace WSN{ 45 inline int main(){ 46 n=read();m=read(); 47 for(int i=1;i<=m;i++){ 48 int a=read(),b=read(); 49 ot[a]++; in[b]++; add(a,b); 50 } 51 for(int i=1;i<=n;i++){ 52 if(!vis[i]){ 53 dfs(i); 54 if(!in[i]) calc(i); 55 } 56 } 57 printf("%d\n",ans); 58 return 0; 59 } 60 } 61 signed main(){return WSN::main();}
T2 时间机器
不难发现这是个死贪心(然而考场上少判断就贪假了。。)
众所周知,贪心只有0分和100分。。。
不过想要拿到100分还要使用$set$
找到所有满足节点范围左端点限制的电阻,然后将其右端点插入set中,
依次找到符合电压范围的后继右端点电阻,减去个数就行
打的时候好好想着有没有可能假的地方,否则就会假。。。
注意细节
新技巧:
1.$set$快速维护
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int min(int a,int b){return a<b?a:b;} 4 inline int read(){ 5 int x=0,f=1; char ch=getchar(); 6 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 7 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 8 return x*f; 9 } 10 const int NN=5e4+5; 11 int T,n,m; 12 struct nod{ 13 int id,r; 14 friend bool operator<(nod a,nod b){return a.r==b.r? a.id<b.id : a.r<b.r;} 15 };set<nod> s; 16 struct node{int r,sum,l;}; node U[NN],R[NN]; 17 inline bool cmp(node a,node b){return a.l==b.l?a.r<b.r: a.l<b.l;} 18 namespace WSN{ 19 inline int main(){ 20 // FILE *A=freopen("1.in","r",stdin); 21 T=read(); 22 while(T--){ 23 s.clear(); 24 n=read();m=read(); 25 for(int i=1;i<=n;i++) U[i].l=read(),U[i].r=read(),U[i].sum=read(); 26 for(int i=1;i<=m;i++) R[i].l=read(),R[i].r=read(),R[i].sum=read(); 27 sort(U+1,U+n+1,cmp); sort(R+1,R+m+1,cmp); 28 nod st; st.r=0x3fffffff,st.id=0; s.insert(st); 29 bool f=0; int j=1; 30 for(int i=1;i<=n;i++){ 31 nod g; 32 while(R[j].l<=U[i].l&&j<=m) 33 g.id=j,g.r=R[j].r,j++,s.insert(g); 34 g.r=U[i].r,g.id=0;//将t设置为电压右端点,找到其后继点 35 while(U[i].sum){ 36 g=*s.lower_bound(g); 37 if(g.r==0x3fffffff) break;//无满足电阻,跳出判断 38 int mn=min(R[g.id].sum,U[i].sum); 39 U[i].sum-=mn; 40 R[g.id].sum-=mn; //减去此类满足的电阻个数 41 if(!R[g.id].sum) s.erase(g);//如果此种类全无,删除此种类电阻 42 } 43 if(U[i].sum){ f=1; break;}//如果最后把所有满足电阻都删掉但是节点还有剩余,直接输出 44 } 45 if(f){puts("No");continue;} 46 if(!f){puts("Yes"); continue;} 47 } 48 return 0; 49 } 50 } 51 signed main(){return WSN::main();}
T3 weight
此题非常牛皮。。
他说最小生成树,就先生成树。
然后将边分为树边和非树边,进行判断。
如果是非树边,他只能最大变成他紧连着的树边里最大的那一个
如果是树边,他顶多变成非树边-1
那么,除了使用数链剖分加线段树维护树边最大值以外,
还要用线段树维护一个最小值(打在一个线段树里,但不用pushup,因为每一段毫无联系(或者说没用),只需下放信息)
查询最小值的话只需要查把边权下放到的那个点即可
在树剖求max时顺便更新最小值
输出的时候还要判断联通
涉及知识点:
1.最小生成树
2.树链剖分+线段树
3.有关边权下放的性质(利用其边权总下放在更深的节点上)
4.并查集判断联通
1 #include<bits/stdc++.h> 2 #define lid (id<<1) 3 #define rid (id<<1|1) 4 using namespace std; 5 inline int max(int a,int b){return a>b?a:b;} 6 inline int min(int a,int b){return a<b?a:b;} 7 inline void swap(int &x,int &y){x^=y^=x^=y;} 8 inline int read(){ 9 int x=0,f=1; char ch=getchar(); 10 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 11 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 12 return x*f; 13 } 14 const int NN=700005,MM=1e6+5,inf=0x7fffffff; 15 int n,m,a,ff[NN],w[NN],ans[MM]; 16 int dfn[NN],rk[NN],son[NN],fa[NN],top[NN],dep[NN],siz[NN],cnt; 17 bool vis[MM]; 18 struct node{int id,u,v,w;};node mp[NN]; 19 struct SNOW{int from,to,val,next;};SNOW e[MM]; int head[NN],rp; 20 inline void add(int x,int y,int z){e[++rp]=(SNOW){x,y,z,head[x]}; head[x]=rp;} 21 inline bool cmp(node a,node b){return a.w<b.w;} 22 inline int getfa(int x){return ff[x]=((ff[x]==x)?x:getfa(ff[x]));} 23 inline void kru(){ 24 int seg=0; sort(mp+1,mp+m+1,cmp); 25 for(int i=1;i<=n;i++) ff[i]=i; 26 for(int i=1;i<=m;i++){ 27 int x=mp[i].u,y=mp[i].v,ID=mp[i].id; 28 if(getfa(x)!=getfa(y)){ 29 ff[getfa(x)]=getfa(y); 30 add(x,y,mp[i].w); 31 add(y,x,mp[i].w); 32 seg++; vis[ID]=true; 33 }if(seg==n-1) break; 34 } 35 } 36 inline void dfs1(int f,int x){ 37 siz[x]=1; fa[x]=f; dep[x]=dep[f]+1; 38 for(int i=head[x];i;i=e[i].next){ 39 int y=e[i].to; 40 if(y==f) continue; 41 w[y]=e[i].val; 42 dfs1(x,y); 43 siz[x]+=siz[y]; 44 if(siz[son[x]]<siz[y]) son[x]=y; 45 } 46 } 47 inline void dfs2(int x,int t){ 48 dfn[x]=++cnt; rk[cnt]=x; top[x]=t; 49 if(!son[x]) return; dfs2(son[x],t); 50 for(int i=head[x];i;i=e[i].next){ 51 int y=e[i].to; 52 if(y!=fa[x]&&y!=son[x]) dfs2(y,y); 53 } 54 } 55 struct SNOWtree{ 56 int ll[NN<<2+5],rr[NN<<2+5]; 57 int minn[NN<<2+5],maxn[NN<<2+5],lzy[NN<<2+5]; 58 inline void pushup(int id){ 59 lzy[id]=min(lzy[lid],lzy[rid]); 60 minn[id]=min(minn[lid],minn[rid]); 61 maxn[id]=max(maxn[lid],maxn[rid]); 62 } 63 inline void pushdown(int id){ 64 if(lzy[id]==inf||ll[id]==rr[id]) return; 65 minn[lid]=min(minn[lid],lzy[id]); 66 minn[rid]=min(minn[rid],lzy[id]); 67 lzy[lid]=min(lzy[lid],lzy[id]); 68 lzy[rid]=min(lzy[rid],lzy[id]); 69 lzy[id]=inf; 70 } 71 inline void build(int id,int l,int r){ 72 ll[id]=l; rr[id]=r; 73 if(l==r){ 74 maxn[id]=w[rk[l]]; 75 minn[id]=lzy[id]=inf; 76 return; 77 } 78 int mid=l+r>>1; 79 build(lid,l,mid); build(rid,mid+1,r); 80 pushup(id); 81 } 82 inline void update(int id,int l,int r,int val){ 83 if(l<=ll[id]&&rr[id]<=r){ 84 minn[id]=min(minn[id],val); 85 lzy[id]=min(lzy[id],val); 86 return; 87 } 88 pushdown(id); 89 if(l<=rr[lid]) update(lid,l,r,val); 90 if(r>=ll[rid]) update(rid,l,r,val); 91 // minn[id]=min(minn[lid],minn[rid]); 92 } 93 inline int query_max(int id,int l,int r){ 94 if(l<=ll[id]&& rr[id]<=r) return maxn[id]; 95 int ans=0; 96 if(l<=rr[lid]) ans=max(ans,query_max(lid,l,r)); 97 if(r>=ll[rid]) ans=max(ans,query_max(rid,l,r)); 98 return ans; 99 } 100 inline int query_min(int id,int pos){ 101 if(ll[id]==rr[id]) return minn[id]; 102 int mid=ll[id]+rr[id]>>1,ans=inf; 103 pushdown(id); 104 if(pos<=mid) ans=min(ans,query_min(lid,pos)); 105 else ans=min(ans,query_min(rid,pos)); 106 return ans; 107 } 108 }tr; 109 inline int MAX(int x,int y,int val){ 110 int ans=0; 111 while(top[x]!=top[y]){ 112 if(dep[top[x]]<dep[top[y]]) swap(x,y); 113 ans=max(ans,tr.query_max(1,dfn[top[x]],dfn[x])); 114 tr.update(1,dfn[top[x]],dfn[x],val-1); 115 x=fa[top[x]]; 116 }if(dfn[x]>dfn[y]) swap(x,y); 117 ans=max(ans,tr.query_max(1,dfn[x]+1,dfn[y])); 118 tr.update(1,dfn[x]+1,dfn[y],val-1); 119 return ans; 120 } 121 namespace WSN{ 122 inline int main(){ 123 // freopen("weight1.in","r",stdin); 124 n=read(); m=read(); a=read(); 125 for(int i=1;i<=m;i++) mp[i].u=read(),mp[i].v=read(),mp[i].w=read(),mp[i].id=i; 126 kru(); dfs1(0,1); dfs2(1,1); tr.build(1,1,n); int root=getfa(1); 127 for(int i=1;i<=m;i++) if(!vis[mp[i].id]){ 128 if(getfa(mp[i].u)!=root) ans[mp[i].id]=0; 129 else ans[mp[i].id]=MAX(mp[i].u,mp[i].v,mp[i].w)-1; 130 } 131 for(int i=1;i<=m;i++) if(vis[mp[i].id]){ 132 if(getfa(mp[i].u)!=root) ans[mp[i].id]=0; 133 else{ 134 if(dep[mp[i].u]>dep[mp[i].v]){ 135 ans[mp[i].id]=tr.query_min(1,dfn[mp[i].u]); 136 } 137 else ans[mp[i].id]=tr.query_min(1,dfn[mp[i].v]); 138 } 139 } 140 for(int i=1;i<=m;i++){ 141 if(ans[i]==inf) printf("-1 "); 142 else printf("%d ",ans[i]); 143 } 144 return 0; 145 } 146 } 147 signed main(){return WSN::main();}

浙公网安备 33010602011771号