2021 SHCPC 简单题杂补
我的水平怎么这么低???
H. Life is a Game
题意: 给一张带权无向图,点有点权,有 \(q\) 次查询,每次查询给定初始点 \(u\) 和初始点数 \(k\),当你走到一个点时可以让你的持有点数增加该点点权,每个点权只能被加一次。你能经过一条边到达另一个点当且仅当你当前的持有点数大于等于边权。求最终持有点数。\(n,m,q\le 2\times10^5\)
差点把 kruskal 重构树忘的一干二净。
一个显然的事实是我们走的边一定是最小生成树上的边,因为原题的限制跟最小瓶颈路很像,而最小瓶颈树等于最小生成树。
然后又一个显然的事实是我们一定选当前连通块内的边权最小的出边往外扩展。考虑建出 kruskal 生成树,由于 kruskal 生成树的优美性质,根节点代表的边权一定是子树内最大的,因此当我们在 kruskal 重构树上一个点向父亲扩展后,一定先把父亲子树内的权值全吃掉。设子树内点权和为 \(sum\),该点代表的边权为 \(a_i\),则能扩展的条件是 \(k+sum_u\ge a_{fa_u}\),维护 \(a_{fa_u}-sum_u\) 的最大值然后树上倍增即可。复杂度单 log。
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0);
#define OTIE cout.tie(0);
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
int qwqx=0,qwqf=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
if(qwqx<0){qwqx=-qwqx;putchar('-');}
int qwqy=0;static char qwqz[40];
while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
while(qwqy--)putchar(qwqz[qwqy]);if(ch)putchar(ch);
}
bool Mbg;
const int maxn=2e5+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,m,Q;
int a[maxn],sum[maxn];
struct edge{
int u,v,w;
bool operator<(const edge &p)const{return w<p.w;}
}e[maxn];
int fafa[maxn];
int getf(int x){return fafa[x]==x?x:fafa[x]=getf(fafa[x]);}
vector<int>G[maxn];
int f[maxn][20],g[maxn][20];
void dfs0(int x){
if(x<=n)sum[x]=a[x];
for(int u:G[x])dfs0(u),sum[x]+=sum[u];
}
void dfs(int x,int y){
f[x][0]=y,g[x][0]=a[y]-sum[x];
rep(i,1,16)f[x][i]=f[f[x][i-1]][i-1],g[x][i]=max(g[x][i-1],g[f[x][i-1]][i-1]);
for(int u:G[x])dfs(u,x);
}
inline void solve_the_problem(){
n=rd(),m=rd(),Q=rd();
a[0]=0x7fffffff;
rep(i,1,n)a[i]=rd();
rep(i,1,m)e[i].u=rd(),e[i].v=rd(),e[i].w=rd();
sort(e+1,e+m+1);
rep(i,1,n<<1)fafa[i]=i;
int ucnt=n;
rep(i,1,m){
int x=getf(e[i].u),y=getf(e[i].v);
if(x!=y){
++ucnt;
a[ucnt]=e[i].w;
G[ucnt].emplace_back(x),G[ucnt].emplace_back(y);
// printf("edge:"),write(x,32),write(y,32),write(ucnt,32),write(e[i].w);
fafa[x]=fafa[y]=ucnt;
}
}
dfs0(ucnt);
dfs(ucnt,0);
while(Q--){
int x=rd(),k=rd();
per(i,16,0)if(k>=g[x][i])x=f[x][i];
write(sum[x]+k);
}
}
bool Med;
signed main(){
// freopen(".in","r",stdin);freopen(".out","w",stdout);
fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
int _=1;
while(_--)solve_the_problem();
}
/*
8 10 2
3 1 4 1 5 9 2 6
1 2 7
1 3 11
2 3 13
3 4 1
3 6 31415926
4 5 27182818
5 6 1
5 7 23333
5 8 55555
7 8 37
1 7
8 30
*/
J. Two Binary Strings Problem
题意: 有 01 串 \(a,b\),设 \(f(l,r)=[\sum_{i=l}^r a_i>\frac{r-l+1}{2}]\),对每个 \(k\) 求其是否满足 \(\forall 1\le i\le n,f(\max(1,i-k+1),i)=b_i\)。\(\sum n\le 5\times10^4\)
写成前缀和的形式:\(s_r-s_{l-1}>\frac{r-l+1}{2}\),2 乘过去得 \(2s_r-2s_{l-1}>r-(l-1)\),移项得 \(2s_r-r>2s_{l-1}-(l-1)\),令 \(s'_i=2s_i-i\)(下文的 \(s_i\) 指的是 \(s'_i\)),则 \(f(l,r)=[s_r>s_{l-1}]\),两边只和本身的下标有关。
考虑扫描线 \(i\),维护一个 bitset \(N\) 表示序列中 \(s_j<s_i\) 的 \(j\) 的集合。由于 \(|s_i-s_{i-1}|=1\),所以该 bitset 的更新也是好做的,只需预处理 \(O(n)\) 个 bitset 表示 \(s_j=k\) 的 \(j\) 的集合。如何判定此时的 \(k\) 是否合法?先考虑 \(i-k\ge 1\) 的正常情况,再维护一个 bitset \(K\) 表示 \(k\) 的合法情况,出于一些原因第 \(i\) 个位置维护的是 \(k=n-i+1\) 的合法情况。以 \(b_i=1\) 为例,若 \(N_{i-1}\) 为 1,说明此时 \(k\) 是合法的;反之不合法。若 \(N_{i-2}\) 为 1 则 \(k=2\) 合法,等等。这样我们只需要将 \(N\) 右移位至 \(i-1\) 与 \(n\) 对齐然后和 \(K\) 与起来即可。注意右移产生的 0 需要想办法将其变成 1。对于 \(i-k<0\) 的特殊情况,一个 \([s_i>0]\neq b_i\) 的位置能让一段后缀之内的 \(k\) 全部倒闭,记个变量就行。复杂度 \(O(\frac{n^2}{\omega})\),注意空间。
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0);
#define OTIE cout.tie(0);
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
int qwqx=0,qwqf=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
if(qwqx<0){qwqx=-qwqx;putchar('-');}
int qwqy=0;static char qwqz[40];
while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
while(qwqy--)putchar(qwqz[qwqy]);if(ch)putchar(ch);
}
bool Mbg;
const int maxn=5e4+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n;
char a[maxn],b[maxn];
int s[maxn];
bitset<maxn>k,eq[maxn],neq,I;
void init(){
k.set(),neq.reset(),I.set();
rep(i,0,n)eq[i].reset();
}
inline void solve_the_problem(){
n=rd(),scanf("%s%s",a+1,b+1);
init();
int delta=0;
rep(i,1,n)s[i]=s[i-1]+2*(a[i]-'0')-1,ckmn(delta,s[i]);
delta=-delta;
rep(i,1,n)eq[s[i]+delta][i]=1;
int lim=n+1;
rep(i,0,delta-1)neq^=eq[i];
rep(i,1,n){
const int op=n-i+1;
if((s[i]>0)!=(b[i]-'0'))ckmn(lim,i);
if(s[i]==s[i-1]+1)neq^=eq[s[i-1]+delta];
else neq^=eq[s[i]+delta];
if(b[i]=='1')k&=(neq<<op)|I;
else k&=(~(neq<<op))|I;
I[op]=0;
}
rep(i,1,n)write(i>=lim?0:k[n-i+1],0);P__;
}
bool Med;
signed main(){
// freopen(".in","r",stdin);freopen(".out","w",stdout);
fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
int _=rd();
while(_--)solve_the_problem();
}
/*
2
5
11010
11000
8
11110000
11111100
-------
1
8
11000110
11000110
output:
10000000
*/

浙公网安备 33010602011771号