20250815 杂题
P4643 [国家集训队] 阿狸和桃子的游戏

发现每个边权可以分摊到两个点上。
因为你考虑,这样的话差值不会变,和也不会变。
匿名

首先dij是可以多源的。
所以预处理出来每个点举例守卫的距离。
然后考虑边权是两个点权的较小值,发现你求出来最大生成树的话,最优路径一定在上面(一个套路?可惜我不知道)
然后你每次在生成树上做即可。

考虑序列分治,最大值在一边的话,另一边一定是连续前缀,所以问题可以转化为,维护一个数据结构,支持插入/删除一个数 xx,查询当前集合内含有的某个数 xx 的子集/超集数量。。

P3332 [ZJOI2013] K大数查询
整体二分
抽象在于。
二分的是答案,也就是l,r,mid是答案,但是你要处理的L,R,是序列,所以比较难理解。
你要实现一个函数slove(l,r);
假设你当前二分到mid,你需要将当前区间转化为两个可以求解的子问题。
具体的,对于修改操作,因为当前答案是mid,所以修改操作显然只会对后面的产生贡献,进行修改实施插到后半部分,否则放到前半部分。
查询操作,因为当前答案是问题的l,r的目前值,所以对于小于mid的查询,放到左面,否则减去mid放到右面。
对于处理修改,你需要维护支持区间加,区间清零,区间查询的线段树,每次查询
然后递归即可。
其中线段树维护的是当前的序列状态,对于一个点i,线段树是答案为在答案为mid的情况下,序列i的点目前有多少个。
#include<bits/stdc++.h>
using namespace std;
#define int long long
constexpr int maxn = 1e6 + 10;
struct Ask{
int op, l, r, id;
int val;
}q[maxn], tl[maxn], tr[maxn];
int tag[maxn << 2], rec[maxn << 2];
int ans[maxn];
int sum[maxn];
int n, m, Q;
inline int ls(int x){return x << 1;}
inline int rs(int x){return x << 1 | 1;}
inline void pushdown(int l,int r,int d){
if(rec[d]){
rec[d] = 0;
tag[ls(d)] = tag[rs(d)] = sum[ls(d)] = sum[rs(d)] = 0;
rec[ls(d)] = 1, rec[rs(d)] = 1;
}
if(tag[d]){
int mid = (l + r) >> 1;
tag[ls(d)] += tag[d];
tag[rs(d)] += tag[d];
sum[ls(d)] += tag[d] * (mid - l + 1);
sum[rs(d)] += tag[d] * (r - mid);
tag[d] = 0;
}
}
inline void pushup(int d){
sum[d] = sum[ls(d)] + sum[rs(d)];
}
void add(int L,int R,int l,int r,int d,int k){
if(L <= l && r <= R){
tag[d] += k;
sum[d] += (r - l + 1) * k;
return;
}
pushdown(l, r, d);
int mid = (l + r) >> 1;
if(L <= mid) add(L,R,l,mid,ls(d),k);
if(R > mid) add(L,R,mid+1,r,rs(d),k);
pushup(d);
}
int query(int L,int R,int l,int r,int d){
if(L <= l && r <= R) return sum[d];
int mid = (l + r) >> 1;
int res = 0;
pushdown(l,r,d);
if(L <= mid) res += query(L,R,l,mid,ls(d));
if(R > mid) res += query(L,R,mid+1,r,rs(d));
return res;
}
void slove(int st,int ed,int l,int r){
if(l == r){
for(int i = st;i <= ed;i++){
if(q[i].op == 2) ans[q[i].id] = l;
}
return;
}
int mid = (l + r) >> 1;
bool fl = 0, fr = 0;
int L = 0, R = 0;
rec[1] = 1;
tag[1] = sum[1] = 0;
for(int i = st;i <= ed;i++){
if(q[i].op == 1){
if(q[i].val > mid){
add(q[i].l,q[i].r,1,n,1,1);
tr[++R] = q[i];
}else{
tl[++L] = q[i];
}
}
else{
int val = query(q[i].l,q[i].r,1,n,1);
if(val < q[i].val){
q[i].val -= val;
fl = 1;
tl[++L] = q[i];
}
else{
fr = 1;
tr[++R] = q[i];
}
}
}
for(int i = 1;i <= L;i++) q[st+i-1] = tl[i];
for(int i = L+1;i <= L+R;i++) q[st+i-1] = tr[i - L];
if(fl) slove(st,st+L-1,l,mid);
if(fr) slove(st+L,ed,mid+1,r);
}
signed main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i = 1;i <= m;i++){
cin>>q[i].op>>q[i].l>>q[i].r>>q[i].val;
if(q[i].op == 2) q[i].id = ++Q;
}
slove(1,m,-n,n);
for(int i = 1;i <= Q;i++){
cout<<ans[i]<<endl;
}
return 0;
}
P9130 [USACO23FEB] Hungry Cow P
一种单侧递归线段树,类似楼房重建。




注意,nop更新在pull时,可以保证是及时的。
nopB是A的rem和B的num的贡献之和

浙公网安备 33010602011771号