题解:P12461 [Ynoi Easy Round 2018] 星野爱
Solution
纯套路题。
看到数据范围联想到分块。而这种东西想暴力做一个区间复杂度是
注意我们要删掉所有零度点。不然直接这么做复杂度会爆掉(也可以按照
我们把问题按照询问是否是散块、查询是否是散块分成
- 散块修改,散块查询。全部暴力就行。
- 散块修改,整块查询。对于每一块,计算修改一个点对整个块产生的贡献(很可以直接记下来空间会爆,所以只能对每个块做一遍)。
- 整块修改,散块查询。计算修改一个块对一个点产生的贡献(很容易发现和上面那个本质相同,可以节省一些运算量)。
- 整块修改,整块查询。在计算出一个块对一个点的贡献之后对每个块做一遍前缀和即可。
复杂度为
这种带权分块要注意,普通分块题目会把左右两端都当成散块(哪怕他们实际上是一个整块,并不影响复杂度)。而带权分块必须把他们当成整块,不然会被某个点极大的情况卡掉。
#include<bits/stdc++.h>
#define ull unsigned long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=2e5+10,B=1500;
int n,m,k,q,tot,op[MAXN],l[MAXN],r[MAXN],rnk[MAXN];
int ex[MAXN],ey[MAXN];
vector<int> g[MAXN],G[MAXN];
int L[MAXN],R[MAXN],bel[MAXN];
ull val[MAXN],ad[MAXN],EF[MAXN],ef[MAXN],pre[MAXN];
int sp[MAXN],to[MAXN*2],deg[MAXN];
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m>>q;
ffor(i,1,m) {int u,v;cin>>u>>v,ex[i]=u,ey[i]=v,g[u].push_back(v),g[v].push_back(u);}
ffor(i,1,n) if(!g[i].empty()) rnk[i]=++tot;
else rnk[i]=rnk[i-1];
ffor(i,1,m) {
int u=rnk[ex[i]],v=rnk[ey[i]];
G[u].push_back(v),G[v].push_back(u);
}
int mt=0;
ffor(i,1,n) {sp[i]=mt+1;for(auto v:G[i]) deg[i]++,to[++mt]=v;}
ffor(i,1,q) {
cin>>op[i]>>l[i]>>r[i];
if(op[i]==1) cin>>val[i];
l[i]=rnk[l[i]-1]+1;
r[i]=rnk[r[i]];
}
int lst=1,tmp=0;
n=tot;
ffor(i,1,n+1) {
tmp+=deg[i];
if(tmp>=B||i==n+1) {
if(lst<=i-1) ++k,L[k]=lst,R[k]=i-1;
lst=i,tmp=deg[i];
}
}
ffor(i,1,k) ffor(j,L[i],R[i]) bel[j]=i;
ffor(i,1,q) if(l[i]<=r[i]) {
if(op[i]==1) {
if(bel[l[i]]==bel[r[i]]&&(l[i]!=L[bel[l[i]]]||r[i]!=R[bel[r[i]]])) ffor(u,l[i],r[i]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) ad[v]+=val[i];
else {
if(l[i]!=L[bel[l[i]]]) ffor(u,l[i],R[bel[l[i]]]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) ad[v]+=val[i];
if(r[i]!=R[bel[r[i]]]) ffor(u,L[bel[r[i]]],r[i]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) ad[v]+=val[i];
}
}
else {
if(bel[l[i]]==bel[r[i]]&&(l[i]!=L[bel[l[i]]]||r[i]!=R[bel[r[i]]])) ffor(u,l[i],r[i]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) val[i]+=ad[v];
if(bel[l[i]]!=bel[r[i]]) {
if(l[i]!=L[bel[l[i]]]) ffor(u,l[i],R[bel[l[i]]]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) val[i]+=ad[v];
if(r[i]!=R[bel[r[i]]]) ffor(u,L[bel[r[i]]],r[i]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) val[i]+=ad[v];
}
}
}
ffor(id,1,k) {
memset(EF,0,sizeof(EF)),memset(ef,0,sizeof(ef));
ffor(u,L[id],R[id]) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) EF[v]++;
ffor(u,1,n) for(int e=sp[u],v=to[e];e<=sp[u]+deg[u]-1;e++,v=to[e]) ef[u]+=EF[v];
ffor(i,1,n) pre[i]=pre[i-1]+ef[i];
ull zad=0,sad=0;
ffor(i,1,q) if(l[i]<=r[i]) {
if(op[i]==1) {
sad+=(pre[r[i]]-pre[l[i]-1])*val[i];
if(l[i]<=L[id]&&R[id]<=r[i]) zad+=val[i];
}
else {
if(l[i]<=L[id]&&R[id]<=r[i]) val[i]+=sad;
if(bel[l[i]]==bel[r[i]]&&(l[i]!=L[bel[l[i]]]||r[i]!=R[bel[r[i]]])) val[i]+=zad*(pre[r[i]]-pre[l[i]-1]);
if(bel[l[i]]!=bel[r[i]]) {
if(l[i]!=L[bel[l[i]]]) val[i]+=zad*(pre[R[bel[l[i]]]]-pre[l[i]-1]);
if(r[i]!=R[bel[r[i]]]) val[i]+=zad*(pre[r[i]]-pre[L[bel[r[i]]]-1]);
}
}
}
}
ffor(i,1,q) if(op[i]==2) cout<<val[i]<<'\n';
return 0;
}