underthetwilight

1

我们考虑这样一个问题:
有一个序列,被划分为了\(k\)个集合,每个集合里的元素在序列上不一定连续,每次进行区间操作,求有多少个集合满足集合里的和小于某个定值

\(1.\) 折半警报器

如果对于每个集合\(id\),其中元素都恰有\(2\)个,那我们考虑将每个元素的阈值设为整体阈值的\(\frac 1 2\),每次区间加变成区间减,假设此二元素分别为\(a,b\),阈值为\(s\),那么有
\(max(a,b)+min(a,b)\le2max(a,b)\)
那么如果\(max(a,b)\le \frac 1 2 s\Rightarrow a+b\le s\)所以,如果\(a,b\le \frac s 2\)则此时一定不超阈值,如果出现\(max(a,b)>\frac s 2\)我们暴力取出\(a,b\)进行修改

\(2.\)二进制警报器

我们设\(t\)为满足\(2^t\le \lceil \frac{s}{k}\rceil\)的最大整数,则我们将原本为\(\frac s 2\)的阈值改为\(2^t\),如果存在某个\(x>2^t\),我们对\(s\)进行修改,如果此时\(2^t>\lceil \frac{s'}{k}\rceil,t\rightarrow t-1\),直到\(t=1\)或\(s\le0\)
复杂度\(O(n\log n\log V),V\)为值域

例题:U676773 污染

题意简述:

存在一个\(n\)个节点的有根树,每个节点属于一个集合\(S\),对于每个集合,有一个阈值\(k\),每次对整个子树内的所有节点加某个值,问每次操作后有多少个集合的权值和大于阈值

\(\text{Solution}:\)

因为是对子树进行操作,显然的可以想到用\(dfs\)序将子树问题转为区间问题

先考虑如果每个集合中都只有两个元素,此时我们使用折半警报器,将阈值设为\(\frac s 2\),每次区间加操作改为区间减,维护区间最小值,当最小值$ \le 0\(时,我们取出两个元素,计算其污染值之和,设其为\)k\(,我们更新\)S\rightarrow S-k=S'\(,将两点阈值重置为\)\frac {S'} 2$
对于每次取出两个点的复杂度是\(O(\log n)\)的,对于每个集合,每次操作至少会让\(S\rightarrow \frac S 2(\)因为警报器触发时一定有一个\(\frac S 2\)被归\(0)\)所以整体复杂度为 \(O(k\log S\log n)\)


现在每个集合有\(t\)个元素,我们考虑延续上方的做法,将阈值设为\(\frac S t\),每次修改复杂度变为\(O(t\log n)\),每次\(S\rightarrow \frac {t-1} t S\),时间复杂度\(O(\sum t\log_{1-\frac 1 t}S\log n)\)近似于\(O(n^2\log S\log n)\),显然无法接受(甚至不如\(O(qn)\)的暴力)


我们考虑优化,我们发现复杂度瓶颈在于\(\frac S t\)比较小,所以警报器的触发非常频繁,对\(S\)的减小幅度也很小,而且每次警报器触发都要\(O(t\log n)\)的处理所有点,我们可以想到,如果将阈值减小,每次如果\(\frac {S'} t\)仍大于阈值,我们就不必取出所有点,只更新\(S\)并重置该点的阈值,当\(\frac{S'} t\)小于阈值再取出所有点修改即可


我们设阈值序列为
\( d_0 > d_1 > d_2 > \cdots > d_m = 1 \)
其中 \(d_0\) 是初始阈值,\(d_j\) 是第\(j\)次全组扫描后更新的阈值。我们要分析该小组的总时间复杂度,再对所有小组求和。

\(\bold{1. 单个小组的代价}\)

记该小组有 \(k\) 个监测点,初始剩余阈值 \(r_j=s\)。

阶段 \(j\):阈值为 \(d_j\)

进入该阶段时,剩余阈值为 \(r_j\),满足
\( k\,d_j \le r_j < k\,d_{j-1} \)
因为上一次切换时,\(d_{j-1}\) 不满足 \(k d_{j-1} \le r\),所以 \(r < k d_{j-1}\);而新阈值 \(d_j\) 必须满足 \(k d_j \le r\),否则会继续调整。

在该阶段内,每次触发至少结算 \(d_j\) 的污染。因此该阶段最多触发

\[\frac{r_j}{d_j} < \frac{k\,d_{j-1}}{d_j} \]

次。
每次触发需要一次单点查询和单点赋值,代价 \(O(\log n)\)。

全组扫描

每次从 \(d_{j-1}\) 切换到 \(d_j\) 时,都会执行一次全组扫描,遍历该小组所有 \(k\) 个监测点,每个点做一次查询和赋值,代价 \(O(k \log n)\)。
共有 \(m\) 次切换(加上可能的初始扫描),所以全组扫描总代价\(O(m \cdot k \log n)\)

单个小组总代价

触发总次数上界:

\[\sum_{j=1}^{m} \frac{k\,d_{j-1}}{d_j} = k \sum_{j=1}^{m} \frac{d_{j-1}}{d_j} \]

加上全组扫描的 \(m\) 次遍历,总操作次数:
\(k \left( \sum_{j=1}^{m} \frac{d_{j-1}}{d_j} + m \right)\)
每次操作 \(O(\log n)\),所以单个小组总时间:

\[O\left( k \left( \sum_{j=1}^{m} \frac{d_{j-1}}{d_j} + m \right) \log n \right) \]


2. 所有小组求和

设共有\(G\)个小组,第 \(i\) 个小组有 \(k_i\) 个监测点,阈值序列长度为 \(m_i\)。则总时间(不含工厂区间加)为:

\[O\left( \sum_{i=1}^{G} k_i \left( \sum_{j=1}^{m_i} \frac{d_{i,j-1}}{d_{i,j}} + m_i \right) \log n \right) \]

再加上\(q\)次工厂区间加,每次 \(O(\log n)\):

\[O\left( q \log n + \sum_{i=1}^{G} k_i \left( \sum_{j=1}^{m_i} \frac{d_{i,j-1}}{d_{i,j}} + m_i \right) \log n \right) \]


3. 结论

对于任意阈值序列 \((d_0, d_1, \dots, d_m=1)\),总时间复杂度为

\[O(q\log n+\sum_{i=1}^{G}k_i( \sum_{j=1}^{m_i} \frac{d_{i,j-1}}{d_{i,j}} + m_i ) \log n ) \]

当我们取\(d_i=2^i\)时,时间复杂度为

\[O(q\log n+n\log S\log n) \]

\(\text{Code:}\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+7;
const int mod=998244353;
const int INF=1e18;
int c,n,m,q,a[N],s[N],dfn[N],ap[N],tot,ed[N];
int base[N],cnt[N],ans,tp[N]; 
bool BJ[N];
vector<int> e[N],ele[N];
void dfs(int x,int ff){
	dfn[x]=++tot;ed[x]=tot;
	ap[tot]=a[x];
	for(auto y:e[x]){
		if(y==ff) continue;
		dfs(y,x);
		ed[x]=max(ed[x],ed[y]);
	}
}
int mp(int a,int b){
	if(b==0) return 1;
	int sum=mp(a,b>>1);
	sum=sum*sum%mod;
	if(b&1) sum=sum*a%mod;
	return sum;
}
int get(int a,int b){
	if(b==0) return 1;int k=(a+b-1)/b;if(k<=1) return 1;
	int id=upper_bound(base,base+63,k)-base;
	return base[id-1];
}
struct node{int l,r,mi,tag;}t[N<<2];
struct Segment{
	void pushup(int u){t[u].mi=min(t[u<<1].mi,t[u<<1|1].mi);}
	void Sakura(int u,int p){
		t[u].mi+=p;
		t[u].tag+=p;
	}
	void pushdown(int u){
		if(t[u].tag){
			Sakura(u<<1,t[u].tag);
			Sakura(u<<1|1,t[u].tag);
			t[u].tag=0;
		}
	}
	void build(int u,int l,int r){
		t[u].l=l,t[u].r=r;
		if(l==r){
			int k=ap[l];
			t[u].mi=tp[k];
			return;
		}int mid=(l+r)>>1;
		build(u<<1,l,mid);build(u<<1|1,mid+1,r);
		pushup(u);
	}
	void update(int u,int l,int r,int k){
		if(t[u].l>=l&&t[u].r<=r){
			Sakura(u,k);
			return ;
		}pushdown(u);
		if(t[u<<1].r>=l) update(u<<1,l,r,k);
		if(t[u<<1|1].l<=r) update(u<<1|1,l,r,k);
		pushup(u);
	}
	void sub(int u,int pos,int x){
		if(t[u].l==t[u].r){
			t[u].mi=x;
			return ;
		}pushdown(u);
		if(t[u<<1].r>=pos) sub(u<<1,pos,x);
		else sub(u<<1|1,pos,x);
		pushup(u);
	}
	int query(int u, int pos) {
    	if(t[u].l==t[u].r) return t[u].mi;
    	pushdown(u);
    	if(pos<=t[u<<1].r) return query(u<<1,pos);
    	else return query(u<<1|1,pos);
	}
	int find(int u) {
	    if(t[u].l==t[u].r) return u;
	    pushdown(u);
	    if(t[u<<1].mi<=0) return find(u<<1);
	    else return find(u<<1|1);
	}
}T;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	base[0]=1;for(int i=1;i<=62;i++) base[i]=base[i-1]*2;
	cin>>c>>n>>m>>q;
	for(int i=2;i<=n;i++){
		int f;cin>>f;
		e[i].push_back(f);
		e[f].push_back(i);
	}
	for(int i=1;i<=n;i++){cin>>a[i];cnt[a[i]]++;}
	for(int i=1;i<=m;i++){
		cin>>s[i];
		tp[i]=get(s[i],cnt[i]);
	}
	dfs(1,0);T.build(1,1,n);
	for(int i=1;i<=n;i++) ele[a[i]].push_back(dfn[i]);
	while(q--){
		int u,x;cin>>u>>x;
		u=u^(c*ans),x=x^(c*ans);
		int l=dfn[u],r=ed[u];
		T.update(1,l,r,-x);
		if(t[1].mi>0){
			cout<<ans<<"\n";
			continue;
		}
		while(t[1].mi<=0){
			int u=T.find(1);
			int pos=t[u].l,id=ap[pos];
			int p=tp[id]-t[u].mi;
			if(BJ[id]){
				T.sub(1,pos,INF);
				continue;
			}
			s[id]-=p;
			T.sub(1,pos,tp[id]);
			if(s[id]<=0){
				BJ[id]=1;
				for(auto k:ele[id])T.sub(1,k,INF);
				ans=(ans+mp(2,id-1))%mod;
				continue;
			}
			if(cnt[id]*tp[id]>s[id]){
				for(auto k:ele[id]){
					int d=T.query(1,k),p=tp[id]-d;
					s[id]-=p;
				}
				if(s[id]<=0){
					BJ[id]=1;
					for(auto k:ele[id])T.sub(1,k,INF);
					ans=(ans+mp(2,id-1))%mod;
					continue;
				}
				while(tp[id]>1&&cnt[id]*tp[id]>s[id]) tp[id]>>=1;
				for(auto k:ele[id]) T.sub(1,k,tp[id]);
			}
		}cout<<ans<<"\n";
	}
	return 0;
}

posted on 2026-10-13 11:27  Underthetwilight  阅读(7)  评论(0)    收藏  举报

导航