根号分治(待补充)
最近有根号分治的题都没那么熟悉,想到了方向感也很差,故写一点题解。
LCA查询
看到题目中的条件
说明
那么对于前者,考虑一开始最朴素的
对于后者,若
跑起来挺快。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,m,dep[N];
int siza,a[N];
int sizb,b[N];
int st[N][18];
vector<int> e[N];
void dfs(int u,int fa){
dep[u] = dep[fa] + 1;
st[u][0] = fa;
for(int i = 1;i<=17;++i)st[u][i] = st[st[u][i-1]][i-1];
for(int v : e[u])if(v ^ fa)dfs(v,u);
}
int LCA(int x,int y){
if(dep[x] > dep[y])swap(x,y);
int t = dep[y] - dep[x];
for(int i = 17;~i;--i)if(t&(1<<i))y = st[y][i];
if(x == y)return x;
for(int i = 17;~i;--i)if(st[x][i] ^ st[y][i])
x = st[x][i], y = st[y][i];
return st[x][0];
}
int vis[N];
int main(){
scanf("%d%d",&n,&m);
for(int i = 1,u,v;i<n;++i){
scanf("%d%d",&u,&v);
e[u].push_back(v),e[v].push_back(u);
}
dfs(1,0);
while(m--){
scanf("%d",&siza); for(int i = 1;i<=siza;++i)scanf("%d",&a[i]);
scanf("%d",&sizb); for(int i = 1;i<=sizb;++i)scanf("%d",&b[i]);
int ans = 0;
if(siza <= 100 && sizb <= 100){
for(int i = 1;i<=siza;++i)
for(int j = 1;j<=sizb;++j)
ans = max(ans,dep[LCA(a[i],b[j])]);
printf("%d\n",ans);
}else{
for(int i = 1;i<=siza;++i){
int now = a[i];
while(now){
if(vis[now] > 0)break;
vis[now] = 1;
now = st[now][0];
}
}
for(int i = 1;i<=sizb;++i){
int now = b[i];
while(now){
if(vis[now] > 0){
if(vis[now] == 1)ans = max(ans,dep[now]);
break;
}
vis[now] = 2;
now = st[now][0];
}
}
memset(vis,0,sizeof (int)*(n+5));
printf("%d\n",ans);
}
}
return 0;
}
CF1997E Level Up
同样考虑二元关系。
可以想到随着
对于
对于
同时
由于
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N = 2e5 + 10;
const int B = 440;
int n,q,f[N],a[N];
int sum[450][N];
bool mark[N];
int rk[N];
inline bool check(int l,int r,int level,int k){
return (r - l + 1) - (sum[level-1][r] - sum[level-1][l-1]) >= k;
}
vector<pii> qry[N];
int ans[N];
int main(){
scanf("%d%d",&n,&q);
for(int i = 1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i] <= B)++sum[a[i]][i];
}
for(int j = 1;j<=B;++j)
for(int i = 1;i<=n;++i)
sum[j][i] += sum[j-1][i] + sum[j][i-1] - sum[j-1][i-1];
for(int i = 1,p,k;i<=q;++i){
scanf("%d%d",&p,&k);
qry[k].push_back({p,i});
}
for(int k = 1;k<=n;++k){
if(qry[k].empty())continue;
if(k <= B){
int level = 1, cnt = 0;
for(int i = 1;i<=n;++i){
mark[i] = 0;
if(a[i] < level){
mark[i] = 1;
continue;
}
++cnt;
if(cnt == k)cnt = 0,++level;
}
for(pii p : qry[k])if(!mark[p.first])ans[p.second] = 1;
}else{
sort(qry[k].begin(),qry[k].end());
int pos = 1,level = 1,it = 0;
while(pos <= n){
int L = pos, R = n, res = n;
while(L <= R){
int mid = L + R >> 1;
if(check(pos,mid,level,k))res = mid, R = mid - 1;
else L = mid + 1;
}
while(it < qry[k].size() && pos <= qry[k][it].first && qry[k][it].first <= res)
rk[qry[k][it].first] = level,++it;
pos = res + 1;
++level;
}
for(pii p : qry[k])ans[p.second] = (a[p.first] >= rk[p.first]);
}
}
for(int i = 1;i<=q;++i)
puts(ans[i] ? "YES" : "NO");
return 0;
}
ABC365G
问题陈述
该办公室保存着进出记录,自记录开始以来,已有
已知所有的人在记录开始时都在办公室外。
按以下格式回答
对于
分析
对于 段数
对于 段数
对于每个
最多只可能有
预处理时间复杂度
本代码已T飞
#include<bits/stdc++.h>
#define se second
#define fi first
using namespace std;
const int N = 2e5 + 10;
typedef pair<int,int> pii;
int n,m;
vector<pii> a,e[N];
int pre[N];
map<pii,int> res;
int sum[N];
bool mark[N];
#define clamp DFJSHSFBSGDRFSRBHBFKBDSJGFDSKDSffhjffghghf
inline int clamp(int l,int r,int x){
if(x >= r)return r;
else if(x <= l)return l;
return x;
}
int query(int x,int y){
if(x > y)swap(x,y);
if(mark[x] || mark[y])return res[{x,y}];
if(e[x].empty() || e[y].empty())return res[{x,y}] = 0;
int it = 0, ans = 0;
for(pii p : e[x]){
int l = p.fi, r = p.se;
ans += clamp(l,r,e[y][it].se) - clamp(l,r,e[y][it].fi);
while(it+1 < e[y].size() && e[y][it+1].fi <= r){
++it;
ans += clamp(l,r,e[y][it].se) - clamp(l,r,e[y][it].fi);
}
}
return res[{x,y}] = ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1,T,P;i<=m;++i){
scanf("%d%d",&T,&P);
a.push_back({T,P});
if(pre[P])e[P].push_back({pre[P],T}),pre[P] = 0;
else pre[P] = T;
}
const int B = 1000;
for(int i = 1;i<=n;++i)
if(e[i].size() >= B){
mark[i] = 1;
for(int j = 1;j<=n;++j)sum[j] = 0;
bool in = 0;
int now = 0, pt = 0;
for(pii p : a){
int T = p.fi, P = p.se;
if(P == i){
now += in * (T - pt);
pt = T; in ^= 1;
}
sum[P] = now + in * (T - pt) - sum[P];
}
for(int j = 1;j<=n;++i)res[{min(i,j),max(i,j)}] = sum[j];
}
int q,x,y; scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】